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:
authorTon Roosendaal <ton@blender.org>2004-09-19 15:47:49 +0400
committerTon Roosendaal <ton@blender.org>2004-09-19 15:47:49 +0400
commitca5b7386e501518157493335e870435017cbb98a (patch)
treedeb4d80d9e371fd5393a12c18698128b98bcfaa4 /source/blender
parentdab46067bf3c3b808a7ba5071e0d51d753651674 (diff)
Part one of editmesh.c refactoring. The huge file has been split in
logical parts, and include files altered to denote internal and external functions. include/editmesh.h: internal calls for editmesh_xxx.c files include/BIF_editmesh.h: external calls for these files src/editmesh.c: basic alloc/lists and in/out editmode, undo, separate src/editmesh_lib.c: basic utility calls for all editmesh_xxx.c (no UI) src/editmesh_add.c: add prim, add duplicate, add vertex/edge/face (UI) src/editmesh_mods.c: selecting, transforming (UI) src/editmesh_loop.c: loop tools like knife, loop select, loop subdiv (UI) src/editmesh_tools.c: other tools (extrude, spin, etc) (UI) And a new file: src/meshtools.c: tools for Mesh outside of editmode (normals, draw flags)
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/include/BIF_editmesh.h193
-rw-r--r--source/blender/include/BIF_meshtools.h47
-rw-r--r--source/blender/include/editmesh.h89
-rw-r--r--source/blender/src/booleanops.c2
-rw-r--r--source/blender/src/buttons_editing.c1
-rw-r--r--source/blender/src/editmesh.c8805
-rw-r--r--source/blender/src/editmesh_add.c699
-rw-r--r--source/blender/src/editmesh_lib.c736
-rw-r--r--source/blender/src/editmesh_loop.c1843
-rw-r--r--source/blender/src/editmesh_mods.c1447
-rw-r--r--source/blender/src/editmesh_tools.c3446
-rw-r--r--source/blender/src/header_view3d.c1
-rw-r--r--source/blender/src/meshtools.c883
-rw-r--r--source/blender/src/space.c1
-rw-r--r--source/blender/src/usiblender.c1
15 files changed, 9412 insertions, 8782 deletions
diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h
index 176cef6c99c..a40c09f4bfe 100644
--- a/source/blender/include/BIF_editmesh.h
+++ b/source/blender/include/BIF_editmesh.h
@@ -30,6 +30,8 @@
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
+/* External for editmesh_xxxx.c functions */
+
#ifndef BIF_EDITMESH_H
#define BIF_EDITMESH_H
@@ -40,139 +42,104 @@ struct Mesh;
struct bDeformGroup;
struct View3D;
-void free_hashedgetab(void);
-void fasterdraw(void);
-void slowerdraw(void);
-void vertexnoise(void);
-void vertexsmooth(void);
-void make_sticky(void);
-void deselectall_mesh(void);
-
-/* For Knife subdivide */
-typedef struct CutCurve {
- short x;
- short y;
-} CutCurve;
-
-void KnifeSubdivide(char mode);
-#define KNIFE_PROMPT 0
-#define KNIFE_EXACT 1
-#define KNIFE_MIDPOINT 2
+/* ******************* editmesh.c */
+extern void make_editMesh(void);
+extern void load_editMesh(void);
+extern void free_editMesh(void);
+extern void remake_editMesh(void);
-CutCurve *get_mouse_trail(int * length, char mode);
-#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
+ /* Editmesh Undo code */
+void undo_free_mesh(struct Mesh *me);
+void undo_push_mesh(char *name);
+void undo_pop_mesh(int steps);
+void undo_redo_mesh(void);
+void undo_clear_mesh(void);
+void undo_menu_mesh(void);
+
+extern void separatemenu(void);
+extern void separate_mesh(void);
+extern void separate_mesh_loose(void);
+
+/* ******************* editmesh_add.c */
+extern void add_primitiveMesh(int type);
+extern void adduplicate_mesh(void);
+extern void addvert_mesh(void);
+extern void addedgeface_mesh(void);
+
+/* ******************* editmesh_lib.c */
+extern int faceselectedAND(struct EditFace *efa, int flag);
+extern void recalc_editnormals(void);
+extern void flip_editnormals(void);
+extern void vertexnormals(int testflip);
-short seg_intersect(struct EditEdge * e, CutCurve *c, int len);
+/* ******************* editmesh_mods.c */
+extern void vertexnoise(void);
+extern void vertexsmooth(void);
+extern void righthandfaces(int select);
+extern void mouse_mesh(void);
-void LoopMenu(void);
-/* End Knife Subdiv */
+extern void deselectall_mesh(void);
+extern void selectconnected_mesh(int qual);
+extern void selectswap_mesh(void);
+
+extern void hide_mesh(int swap);
+extern void reveal_mesh(void);
+
+extern void vertices_to_sphere(void);
/** Aligns the selected TFace's of @a me to the @a v3d,
* using the given axis (0-2). Can give a user error.
*/
-void faceselect_align_view_to_selected(struct View3D *v3d, struct Mesh *me, int axis);
+extern void faceselect_align_view_to_selected(struct View3D *v3d, struct Mesh *me, int axis);
/** Aligns the selected faces or vertices of @a me to the @a v3d,
* using the given axis (0-2). Can give a user error.
*/
-void editmesh_align_view_to_selected(struct View3D *v3d, int axis);
-
-struct EditVert *addvertlist(float *vec);
-struct EditEdge *addedgelist(struct EditVert *v1, struct EditVert *v2, struct EditEdge *example);
-struct EditFace *addfacelist(struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example);
-struct EditEdge *findedgelist(struct EditVert *v1, struct EditVert *v2);
-
-void remedge(struct EditEdge *eed);
+extern void editmesh_align_view_to_selected(struct View3D *v3d, int axis);
-int faceselectedAND(struct EditFace *efa, int flag);
+ /* Selection */
+extern void select_non_manifold(void);
+extern void select_more(void);
+extern void select_less(void);
+extern void selectrandom_mesh(void);
+extern void editmesh_select_by_material(int index);
+extern void editmesh_deselect_by_material(int index);
-void recalc_editnormals(void);
-void flip_editnormals(void);
-void vertexnormals(int testflip);
-/* this is currently only used by the python NMesh module: */
-void vertexnormals_mesh(struct Mesh *me, float *extverts);
+extern void Edge_Menu(void);
+extern void editmesh_mark_seam(int clear);
-void make_editMesh(void);
-void load_editMesh(void);
-void free_editMesh(void);
-void remake_editMesh(void);
+/* ******************* editmesh_loop.c */
-void convert_to_triface(int all);
-
-void righthandfaces(int select);
-
-void mouse_mesh(void);
-
-void selectconnected_mesh(int qual);
-short extrudeflag(short flag,short type);
-void rotateflag(short flag, float *cent, float rotmat[][3]);
-void translateflag(short flag, float *vec);
-short removedoublesflag(short flag, float limit);
-void xsortvert_flag(int flag);
-void hashvert_flag(int flag);
-void subdivideflag(int flag, float rad, int beauty);
-void adduplicateflag(int flag);
-void extrude_mesh(void);
-void adduplicate_mesh(void);
-void split_mesh(void);
+#define KNIFE_PROMPT 0
+#define KNIFE_EXACT 1
+#define KNIFE_MIDPOINT 2
-void separatemenu(void);
-void separate_mesh(void);
-void separate_mesh_loose(void);
+extern void KnifeSubdivide(char mode);
+extern void LoopMenu(void);
-void loopoperations(char mode);
#define LOOP_SELECT 1
#define LOOP_CUT 2
-void vertex_loop_select(void);
-void edge_select(void);
-
-void extrude_repeat_mesh(int steps, float offs);
-void spin_mesh(int steps,int degr,float *dvec, int mode);
-void screw_mesh(int steps,int turns);
-void selectswap_mesh(void);
-void addvert_mesh(void);
-void addedgeface_mesh(void);
-void delete_mesh(void);
-void add_primitiveMesh(int type);
-void hide_mesh(int swap);
-void reveal_mesh(void);
-void beauty_fill(void);
-void join_triangles(void);
-void edge_flip(void);
-void join_mesh(void);
-void sort_faces(void);
-void vertices_to_sphere(void);
-void fill_mesh(void);
-
-void bevel_menu();
-
-/* Editmesh Undo code */
-void undo_free_mesh(struct Mesh *me);
-void undo_push_mesh(char *name);
-void undo_pop_mesh(int steps);
-void undo_redo_mesh(void);
-void undo_clear_mesh(void);
-void undo_menu_mesh(void);
-
-/* Selection */
-void select_non_manifold(void);
-void select_more(void);
-void select_less(void);
-void selectrandom_mesh(void);
-
-void Edge_Menu(void);
-
-void editmesh_select_by_material(int index);
-void editmesh_deselect_by_material(int index);
-
-void editmesh_mark_seam(int clear);
-
+extern void loopoperations(char mode);
+extern void vertex_loop_select(void);
+
+/* ******************* editmesh_tools.c */
+extern void convert_to_triface(int all);
+extern short removedoublesflag(short flag, float limit);
+extern void xsortvert_flag(int flag);
+extern void hashvert_flag(int flag);
+extern void subdivideflag(int flag, float rad, int beauty);
+extern void extrude_mesh(void);
+extern void split_mesh(void);
+extern void extrude_repeat_mesh(int steps, float offs);
+extern void spin_mesh(int steps,int degr,float *dvec, int mode);
+extern void screw_mesh(int steps,int turns);
+extern void delete_mesh(void);
+extern void beauty_fill(void);
+extern void join_triangles(void);
+extern void edge_flip(void);
+extern void fill_mesh(void);
+extern void bevel_menu();
void edge_rotate_selected(void);
-void edge_rotate(struct EditEdge *eed);
#endif
diff --git a/source/blender/include/BIF_meshtools.h b/source/blender/include/BIF_meshtools.h
new file mode 100644
index 00000000000..facfecb0c6e
--- /dev/null
+++ b/source/blender/include/BIF_meshtools.h
@@ -0,0 +1,47 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_MESHTOOLS_H
+#define BIF_MESHTOOLS_H
+
+extern void join_mesh(void);
+extern void make_sticky(void);
+
+extern void fasterdraw(void);
+extern void slowerdraw(void);
+
+extern void vertexnormals_mesh(Mesh *me, float *extverts);
+extern void sort_faces(void);
+
+
+#endif
+
diff --git a/source/blender/include/editmesh.h b/source/blender/include/editmesh.h
new file mode 100644
index 00000000000..d7cd45948c4
--- /dev/null
+++ b/source/blender/include/editmesh.h
@@ -0,0 +1,89 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* Internal for editmesh_xxxx.c functions */
+
+#ifndef EDITMESH_H
+#define EDITMESH_H
+
+#define TEST_EDITMESH if(G.obedit==0) return; \
+ if( (G.vd->lay & G.obedit->lay)==0 ) return;
+
+#define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float));
+
+
+/* ******************* editmesh.c */
+extern void free_editvert(EditVert *eve);
+extern void free_editedge(EditEdge *eed);
+extern void free_editface(EditFace *efa);
+
+extern void free_vertlist(ListBase *edve);
+extern void free_edgelist(ListBase *lb);
+extern void free_facelist(ListBase *lb);
+
+extern void remedge(EditEdge *eed);
+
+extern struct EditVert *addvertlist(float *vec);
+extern struct EditEdge *addedgelist(struct EditVert *v1, struct EditVert *v2, struct EditEdge *example);
+extern struct EditFace *addfacelist(struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example);
+extern struct EditEdge *findedgelist(struct EditVert *v1, struct EditVert *v2);
+
+/* ******************* editmesh_add.c */
+extern void adduplicateflag(int flag);
+
+
+/* ******************* editmesh_lib.c */
+extern int editmesh_nfaces_selected(void);
+extern int editmesh_nvertices_selected(void);
+
+extern int faceselectedOR(EditFace *efa, int flag);
+extern int faceselectedAND(EditFace *efa, int flag);
+
+extern int exist_face(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4);
+extern void flipface(EditFace *efa); // flips for normal direction
+extern int compareface(EditFace *vl1, EditFace *vl2);
+
+extern void delfaceflag(int flag);
+extern short extrudeflag(short flag,short type);
+extern void rotateflag(short flag, float *cent, float rotmat[][3]);
+extern void translateflag(short flag, float *vec);
+
+extern float convex(float *v1, float *v2, float *v3, float *v4);
+
+/* ******************* editmesh_mods.c */
+extern EditEdge *findnearestedge();
+
+/* ******************* editmesh_tools.c */
+
+
+#endif
+
diff --git a/source/blender/src/booleanops.c b/source/blender/src/booleanops.c
index 0ced994fd56..644813c0e01 100644
--- a/source/blender/src/booleanops.c
+++ b/source/blender/src/booleanops.c
@@ -59,12 +59,10 @@
// TODO check to see how many of these includes are necessary
#include "BLI_blenlib.h"
-#include "BLI_editVert.h"
#include "BLI_arithb.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
-#include "BIF_editmesh.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index ed5e86a270b..cb04b9d3faf 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -98,6 +98,7 @@
#include "BIF_editmesh.h"
#include "BIF_editsound.h"
#include "BIF_interface.h"
+#include "BIF_meshtools.h"
#include "BIF_mywindow.h"
#include "BIF_renderwin.h"
#include "BIF_resources.h"
diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c
index ad1acb139fa..8b088a9f0bc 100644
--- a/source/blender/src/editmesh.c
+++ b/source/blender/src/editmesh.c
@@ -62,32 +62,25 @@
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"
-#include "BLI_rand.h"
-
#include "BKE_utildefines.h"
#include "BKE_key.h"
#include "BKE_object.h"
-#include "BKE_texture.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_texture.h"
-#include "BIF_gl.h"
-#include "BIF_graphics.h"
#include "BIF_editkey.h"
-#include "BIF_space.h"
-#include "BIF_toolbox.h"
-#include "BIF_screen.h"
-#include "BIF_interface.h"
#include "BIF_editmesh.h"
+#include "BIF_interface.h"
#include "BIF_mywindow.h"
-#include "BIF_resources.h"
-#include "BIF_glutil.h"
-#include "BIF_cursors.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
#include "BSE_view.h"
#include "BSE_edit.h"
@@ -100,78 +93,21 @@
#include "mydevice.h"
#include "blendef.h"
-#include "nla.h" /* For __NLA : Important - Do not remove! */
#include "render.h"
-#include "GHOST_C-api.h"
-#include "winlay.h"
-#ifdef WIN32
- #ifndef snprintf
- #define snprintf _snprintf
- #endif
-#endif
-
-/****/
-
-static float convex(float *v1, float *v2, float *v3, float *v4);
-
-/* EditMesh Undo */
-void make_editMesh_real(Mesh *me);
-void load_editMesh_real(Mesh *me, int);
-/****/
+/* own include */
+#include "editmesh.h"
+/*
-/* extern ListBase fillvertbase, filledgebase; */ /* scanfill.c, in
- the lib... already in BLI_blenlib.h */
-
-
-extern short editbutflag;
-
-static float icovert[12][3] = {
- {0,0,-200},
- {144.72, -105.144,-89.443},
- {-55.277, -170.128,-89.443},
- {-178.885,0,-89.443},
- {-55.277,170.128,-89.443},
- {144.72,105.144,-89.443},
- {55.277,-170.128,89.443},
- {-144.72,-105.144,89.443},
- {-144.72,105.144,89.443},
- {55.277,170.128,89.443},
- {178.885,0,89.443},
- {0,0,200}
-};
-static short icoface[20][3] = {
- {1,0,2},
- {1,0,5},
- {2,0,3},
- {3,0,4},
- {4,0,5},
- {1,5,10},
- {2,1,6},
- {3,2,7},
- {4,3,8},
- {5,4,9},
- {10,1,6},
- {6,2,7},
- {7,3,8},
- {8,4,9},
- {9,5,10},
- {6,10,11},
- {7,6,11},
- {8,7,11},
- {9,8,11},
- {10,9,11}
-};
-
-/* DEFINES */
-#define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float));
+editmesh.c:
+- add/alloc/free data
+- hashtables
+- enter/exit editmode
-#define TEST_EDITMESH if(G.obedit==0) return; \
- if( (G.vd->lay & G.obedit->lay)==0 ) return;
+*/
-#define FACE_MARKCLEAR(f) (f->f1 = 1)
/* ***************** HASH ********************* */
@@ -183,39 +119,6 @@ struct HashEdge {
struct HashEdge *hashedgetab=NULL;
-/********* qsort routines *********/
-
-
-struct xvertsort {
- float x;
- EditVert *v1;
-};
-
-/* Functions */
-static int vergxco(const void *v1, const void *v2)
-{
- const struct xvertsort *x1=v1, *x2=v2;
-
- if( x1->x > x2->x ) return 1;
- else if( x1->x < x2->x) return -1;
- return 0;
-}
-
-struct facesort {
- long 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;
-}
-
/* ************ ADD / REMOVE / FIND ****************** */
@@ -381,7 +284,7 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example)
return eed;
}
-static void free_editvert (EditVert *eve)
+void free_editvert (EditVert *eve)
{
if (eve->dw) MEM_freeN (eve->dw);
free (eve);
@@ -395,17 +298,17 @@ void remedge(EditEdge *eed)
remove_hashedge(eed);
}
-static void free_editedge(EditEdge *eed)
+void free_editedge(EditEdge *eed)
{
free(eed);
}
-static void free_editface(EditFace *efa)
+void free_editface(EditFace *efa)
{
free(efa);
}
-static void free_vertlist(ListBase *edve)
+void free_vertlist(ListBase *edve)
{
EditVert *eve, *next;
@@ -420,7 +323,7 @@ static void free_vertlist(ListBase *edve)
edve->first= edve->last= NULL;
}
-static void free_edgelist(ListBase *lb)
+void free_edgelist(ListBase *lb)
{
EditEdge *eed, *next;
@@ -433,7 +336,7 @@ static void free_edgelist(ListBase *lb)
lb->first= lb->last= NULL;
}
-static void free_facelist(ListBase *lb)
+void free_facelist(ListBase *lb)
{
EditFace *efa, *next;
@@ -497,138 +400,10 @@ EditFace *addfacelist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed
/* ********* end add / new / find */
-static 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;
-}
-
-static int exist_face(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
-{
- EditMesh *em = G.editMesh;
- 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 1;
- efa= efa->next;
- }
- return 0;
-}
-
-
-static int faceselectedOR(EditFace *efa, int flag)
-{
-
- if(efa->v1->f & flag) return 1;
- if(efa->v2->f & flag) return 1;
- if(efa->v3->f & flag) return 1;
- if(efa->v4 && (efa->v4->f & 1)) return 1;
- return 0;
-}
-
-int faceselectedAND(EditFace *efa, int flag)
-{
- if(efa->v1->f & flag) {
- if(efa->v2->f & flag) {
- if(efa->v3->f & flag) {
- if(efa->v4) {
- if(efa->v4->f & flag) return 1;
- }
- else return 1;
- }
- }
- }
- return 0;
-}
-void recalc_editnormals(void)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa;
- efa= em->faces.first;
- while(efa) {
- if(efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
- else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
- efa= efa->next;
- }
-}
-static void flipface(EditFace *efa)
-{
- if(efa->v4) {
- SWAP(EditVert *, efa->v2, efa->v4);
- SWAP(EditEdge *, efa->e1, efa->e4);
- SWAP(EditEdge *, efa->e2, efa->e3);
- SWAP(unsigned int, efa->tf.col[1], efa->tf.col[3]);
- SWAP(float, efa->tf.uv[1][0], efa->tf.uv[3][0]);
- SWAP(float, efa->tf.uv[1][1], efa->tf.uv[3][1]);
- }
- else {
- SWAP(EditVert *, efa->v2, efa->v3);
- SWAP(EditEdge *, efa->e1, efa->e3);
- SWAP(unsigned int, efa->tf.col[1], efa->tf.col[2]);
- efa->e2->dir= 1-efa->e2->dir;
- SWAP(float, efa->tf.uv[1][0], efa->tf.uv[2][0]);
- SWAP(float, efa->tf.uv[1][1], efa->tf.uv[2][1]);
- }
- if(efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
- else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
-}
-
-
-void flip_editnormals(void)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa;
-
- efa= em->faces.first;
- while(efa) {
- if( faceselectedAND(efa, 1) ) {
- flipface(efa);
- }
- efa= efa->next;
- }
-}
-
-/* ************************ IN & OUT ***************************** */
+/* ************************ IN & OUT EDITMODE ***************************** */
static void edge_normal_compare(EditEdge *eed, EditFace *efa1)
{
@@ -749,164 +524,6 @@ static void edge_drawflags(void)
}
}
-static int contrpuntnorm(float *n, float *puno) /* dutch: check vertex normal */
-{
- float inp;
-
- inp= n[0]*puno[0]+n[1]*puno[1]+n[2]*puno[2];
-
- /* angles 90 degrees: dont flip */
- if(inp> -0.000001) return 0;
-
- return 1;
-}
-
-void vertexnormals(int testflip)
-{
- EditMesh *em = G.editMesh;
- Mesh *me;
- EditVert *eve;
- EditFace *efa;
- float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp;
- float *f1, *f2, *f3, *f4, xn, yn, zn;
- float len;
-
- if(G.obedit && G.obedit->type==OB_MESH) {
- me= G.obedit->data;
- if((me->flag & ME_TWOSIDED)==0) testflip= 0;
- }
-
- if(G.totvert==0) return;
-
- if(G.totface==0) {
- /* fake vertex normals for 'halo puno'! */
- eve= em->verts.first;
- while(eve) {
- VECCOPY(eve->no, eve->co);
- Normalise( (float *)eve->no);
- eve= eve->next;
- }
- return;
- }
-
- /* clear normals */
- eve= em->verts.first;
- while(eve) {
- eve->no[0]= eve->no[1]= eve->no[2]= 0.0;
- eve= eve->next;
- }
-
- /* calculate cosine angles and add to vertex normal */
- efa= em->faces.first;
- while(efa) {
- VecSubf(n1, efa->v2->co, efa->v1->co);
- VecSubf(n2, efa->v3->co, efa->v2->co);
- Normalise(n1);
- Normalise(n2);
-
- if(efa->v4==0) {
- VecSubf(n3, efa->v1->co, efa->v3->co);
- Normalise(n3);
-
- co[0]= saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]);
- co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
- co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
-
- }
- else {
- VecSubf(n3, efa->v4->co, efa->v3->co);
- VecSubf(n4, efa->v1->co, efa->v4->co);
- Normalise(n3);
- Normalise(n4);
-
- co[0]= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
- co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
- co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
- co[3]= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
- }
-
- temp= efa->v1->no;
- if(testflip && contrpuntnorm(efa->n, temp) ) co[0]= -co[0];
- temp[0]+= co[0]*efa->n[0];
- temp[1]+= co[0]*efa->n[1];
- temp[2]+= co[0]*efa->n[2];
-
- temp= efa->v2->no;
- if(testflip && contrpuntnorm(efa->n, temp) ) co[1]= -co[1];
- temp[0]+= co[1]*efa->n[0];
- temp[1]+= co[1]*efa->n[1];
- temp[2]+= co[1]*efa->n[2];
-
- temp= efa->v3->no;
- if(testflip && contrpuntnorm(efa->n, temp) ) co[2]= -co[2];
- temp[0]+= co[2]*efa->n[0];
- temp[1]+= co[2]*efa->n[1];
- temp[2]+= co[2]*efa->n[2];
-
- if(efa->v4) {
- temp= efa->v4->no;
- if(testflip && contrpuntnorm(efa->n, temp) ) co[3]= -co[3];
- temp[0]+= co[3]*efa->n[0];
- temp[1]+= co[3]*efa->n[1];
- temp[2]+= co[3]*efa->n[2];
- }
-
- efa= efa->next;
- }
-
- /* normalise vertex normals */
- eve= em->verts.first;
- while(eve) {
- len= Normalise(eve->no);
- if(len==0.0) {
- VECCOPY(eve->no, eve->co);
- Normalise( eve->no);
- }
- eve= eve->next;
- }
-
- /* vertex normal flip-flags for shade (render) */
- efa= em->faces.first;
- while(efa) {
- efa->f=0;
-
- if(testflip) {
- f1= efa->v1->no;
- f2= efa->v2->no;
- f3= efa->v3->no;
-
- fac1= efa->n[0]*f1[0] + efa->n[1]*f1[1] + efa->n[2]*f1[2];
- if(fac1<0.0) {
- efa->f = ME_FLIPV1;
- }
- fac2= efa->n[0]*f2[0] + efa->n[1]*f2[1] + efa->n[2]*f2[2];
- if(fac2<0.0) {
- efa->f += ME_FLIPV2;
- }
- fac3= efa->n[0]*f3[0] + efa->n[1]*f3[1] + efa->n[2]*f3[2];
- if(fac3<0.0) {
- efa->f += ME_FLIPV3;
- }
- if(efa->v4) {
- f4= efa->v4->no;
- fac4= efa->n[0]*f4[0] + efa->n[1]*f4[1] + efa->n[2]*f4[2];
- if(fac4<0.0) {
- efa->f += ME_FLIPV4;
- }
- }
- }
- /* projection for cubemap! */
- xn= fabs(efa->n[0]);
- yn= fabs(efa->n[1]);
- zn= fabs(efa->n[2]);
-
- if(zn>xn && zn>yn) efa->f += ME_PROJXY;
- else if(yn>xn && yn>zn) efa->f += ME_PROJXZ;
- else efa->f += ME_PROJYZ;
-
- efa= efa->next;
- }
-}
void free_editMesh(void)
{
@@ -919,21 +536,6 @@ void free_editMesh(void)
G.totvert= G.totface= 0;
}
-void make_editMesh(void)
-{
- Mesh *me;
-
- me= get_mesh(G.obedit);
- if (me != G.undo_last_data) {
- G.undo_edit_level= -1;
- G.undo_edit_highest= -1;
- if (G.undo_clear) G.undo_clear();
- G.undo_last_data= me;
- G.undo_clear= undo_clear_mesh;
- }
- make_editMesh_real(me);
-}
-
void make_editMesh_real(Mesh *me)
{
EditMesh *em = G.editMesh;
@@ -997,8 +599,6 @@ void make_editMesh_real(Mesh *me)
*/
eve->keyindex = a;
-#ifdef __NLA
-
if (me->dvert){
eve->totweight = me->dvert[a].totweight;
if (me->dvert[a].dw){
@@ -1007,7 +607,6 @@ void make_editMesh_real(Mesh *me)
}
}
-#endif
}
if(actkey && actkey->totelem!=me->totvert);
@@ -1084,6 +683,23 @@ void make_editMesh_real(Mesh *me)
waitcursor(0);
}
+void make_editMesh(void)
+{
+ Mesh *me;
+
+ me= get_mesh(G.obedit);
+ if (me != G.undo_last_data) {
+ G.undo_edit_level= -1;
+ G.undo_edit_highest= -1;
+ if (G.undo_clear) G.undo_clear();
+ G.undo_last_data= me;
+ G.undo_clear= undo_clear_mesh;
+ }
+ make_editMesh_real(me);
+}
+
+
+
/** Rotates MFace and UVFace vertices in case the last
* vertex index is = 0.
* This function is a hack and may only be called in the
@@ -1094,7 +710,6 @@ void make_editMesh_real(Mesh *me)
* calls/structures, this function resides here.
*/
-
static void fix_faceindices(MFace *mface, EditFace *efa, int nr)
{
int a;
@@ -1191,21 +806,6 @@ static void fix_faceindices(MFace *mface, EditFace *efa, int nr)
}
-
-/* load from EditMode to Mesh */
-
-void load_editMesh()
-{
- Mesh *me;
-
- waitcursor(1);
- countall();
- me= get_mesh(G.obedit);
-
- load_editMesh_real(me, 0);
-}
-
-
void load_editMesh_real(Mesh *me, int undo)
{
EditMesh *em = G.editMesh;
@@ -1219,10 +819,8 @@ void load_editMesh_real(Mesh *me, int undo)
EditEdge *eed;
float *fp, *newkey, *oldkey, nor[3];
int i, a, ototvert, totedge=0;
-#ifdef __NLA
MDeformVert *dvert;
int usedDvert = 0;
-#endif
/* this one also tests of edges are not in faces: */
/* eed->f==0: not in face, f==1: draw it */
@@ -1256,14 +854,11 @@ void load_editMesh_real(Mesh *me, int undo)
else mface= MEM_callocN(G.totface*sizeof(MFace), "loadeditMesh face");
-#ifdef __NLA
if (G.totvert==0) dvert= NULL;
else dvert = MEM_callocN(G.totvert*sizeof(MDeformVert), "loadeditMesh3");
if (me->dvert) free_dverts(me->dvert, me->totvert);
me->dvert=dvert;
-#endif
-
/* 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 */
@@ -1294,7 +889,7 @@ void load_editMesh_real(Mesh *me, int undo)
VECCOPY(nor, eve->no);
VecMulf(nor, 32767.0);
VECCOPY(mvert->no, nor);
-#ifdef __NLA
+
/* NEW VERSION */
if (dvert){
dvert->totweight=eve->totweight;
@@ -1306,7 +901,6 @@ void load_editMesh_real(Mesh *me, int undo)
usedDvert++;
}
}
-#endif
eve->vn= (EditVert *)(long)(a++); /* counter */
@@ -1319,18 +913,14 @@ void load_editMesh_real(Mesh *me, int undo)
eve= eve->next;
mvert++;
-#ifdef __NLA
dvert++;
-#endif
}
-#ifdef __NLA
/* If we didn't actually need the dverts, get rid of them */
if (!usedDvert){
free_dverts(me->dvert, G.totvert);
me->dvert=NULL;
}
-#endif
/* the edges */
if(medge) {
@@ -1570,3483 +1160,178 @@ void remake_editMesh(void)
makeDispList(G.obedit);
}
-/* ********************* TOOLS ********************* */
-
-
-
-void make_sticky(void)
-{
- Object *ob;
- Base *base;
- MVert *mvert;
- Mesh *me;
- MSticky *ms;
- float ho[4], mat[4][4];
- int a;
-
- if(G.scene->camera==0) return;
-
- if(G.obedit) {
- error("Unable to make sticky in Edit Mode");
- return;
- }
- base= FIRSTBASE;
- while(base) {
- if TESTBASELIB(base) {
- if(base->object->type==OB_MESH) {
- ob= base->object;
-
- me= ob->data;
- mvert= me->mvert;
- if(me->msticky) MEM_freeN(me->msticky);
- me->msticky= MEM_mallocN(me->totvert*sizeof(MSticky), "sticky");
-
- /* like convert to render data */
- R.r= G.scene->r;
- R.r.xsch= (R.r.size*R.r.xsch)/100;
- R.r.ysch= (R.r.size*R.r.ysch)/100;
-
- R.afmx= R.r.xsch/2;
- R.afmy= R.r.ysch/2;
-
- R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp);
-
- R.rectx= R.r.xsch;
- R.recty= R.r.ysch;
- R.xstart= -R.afmx;
- R.ystart= -R.afmy;
- R.xend= R.xstart+R.rectx-1;
- R.yend= R.ystart+R.recty-1;
-
- where_is_object(G.scene->camera);
- Mat4CpyMat4(R.viewinv, G.scene->camera->obmat);
- Mat4Ortho(R.viewinv);
- Mat4Invert(R.viewmat, R.viewinv);
-
- RE_setwindowclip(1, -1);
-
- where_is_object(ob);
- Mat4MulMat4(mat, ob->obmat, R.viewmat);
-
- ms= me->msticky;
- for(a=0; a<me->totvert; a++, ms++, mvert++) {
- VECCOPY(ho, mvert->co);
- Mat4MulVecfl(mat, ho);
- RE_projectverto(ho, ho);
- ms->co[0]= ho[0]/ho[3];
- ms->co[1]= ho[1]/ho[3];
- }
- }
- }
- base= base->next;
- }
- allqueue(REDRAWBUTSEDIT, 0);
-}
-
-void fasterdraw(void)
-{
- Base *base;
- Mesh *me;
- MFace *mface;
- int toggle, a;
-
- if(G.obedit) return;
-
- /* reset flags */
- me= G.main->mesh.first;
- while(me) {
- me->flag &= ~ME_ISDONE;
- me= me->id.next;
- }
-
- base= FIRSTBASE;
- while(base) {
- if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
- me= base->object->data;
- if(me->id.lib==0 && (me->flag & ME_ISDONE)==0) {
- me->flag |= ME_ISDONE;
- mface= me->mface;
- toggle= 0;
- for(a=0; a<me->totface; a++) {
- if( (mface->edcode & ME_V1V2) && ( (toggle++) & 1) ) {
- mface->edcode-= ME_V1V2;
- }
- if( (mface->edcode & ME_V2V3) && ( (toggle++) & 1)) {
- mface->edcode-= ME_V2V3;
- }
- if( (mface->edcode & ME_V3V1) && ( (toggle++) & 1)) {
- mface->edcode-= ME_V3V1;
- }
- if( (mface->edcode & ME_V4V1) && ( (toggle++) & 1)) {
- mface->edcode-= ME_V4V1;
- }
- if( (mface->edcode & ME_V3V4) && ( (toggle++) & 1)) {
- mface->edcode-= ME_V3V4;
- }
- mface++;
- }
- }
- }
- base= base->next;
- }
-
- /* important?: reset flags again */
- me= G.main->mesh.first;
- while(me) {
- me->flag &= ~ME_ISDONE;
- me= me->id.next;
- }
-
- allqueue(REDRAWVIEW3D, 0);
-}
+/* load from EditMode to Mesh */
-void slowerdraw(void) /* reset fasterdraw */
+void load_editMesh()
{
- Base *base;
Mesh *me;
- MFace *mface;
- int a;
-
- if(G.obedit) return;
-
- base= FIRSTBASE;
- while(base) {
- if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
- me= base->object->data;
- if(me->id.lib==0) {
-
- mface= me->mface;
-
- for(a=0; a<me->totface; a++) {
-
- mface->edcode |= ME_V1V2|ME_V2V3;
- mface++;
- }
- }
- }
- base= base->next;
- }
-
- allqueue(REDRAWVIEW3D, 0);
-}
-
-
-void convert_to_triface(int all)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa, *efan, *next;
-
- undo_push_mesh("Convert Quads to Triangles");
-
- efa= em->faces.first;
- while(efa) {
- next= efa->next;
- if(efa->v4) {
- if(all || faceselectedAND(efa, 1) ) {
-
- efan= addfacelist(efa->v1, efa->v2, efa->v3, 0, efa);
- efan= addfacelist(efa->v1, efa->v3, efa->v4, 0, efa);
-
- efan->tf.uv[1][0]= efan->tf.uv[2][0];
- efan->tf.uv[1][1]= efan->tf.uv[2][1];
- efan->tf.uv[2][0]= efan->tf.uv[3][0];
- efan->tf.uv[2][1]= efan->tf.uv[3][1];
-
- efan->tf.col[1]= efan->tf.col[2];
- efan->tf.col[2]= efan->tf.col[3];
-
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- }
- efa= next;
- }
-
-}
-
-
-void deselectall_mesh(void) /* toggle */
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- int a;
-
- if(G.obedit->lay & G.vd->lay) {
- a= 0;
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- a= 1;
- break;
- }
- eve= eve->next;
- }
-
- if (a) undo_push_mesh("Deselect All");
- else undo_push_mesh("Select All");
-
- eve= em->verts.first;
- while(eve) {
- if(eve->h==0) {
- if(a) eve->f&= -2;
- else eve->f|= 1;
- }
- eve= eve->next;
- }
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
-}
-
-
-void righthandfaces(int select) /* makes faces righthand turning */
-{
- EditMesh *em = G.editMesh;
- 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->f= 0;
- eed->f1= 0;
- eed= eed->next;
- }
-
- /* count faces and edges */
- totsel= 0;
- efa= em->faces.first;
- while(efa) {
- if(select==0 || faceselectedAND(efa, 1) ) {
- efa->f= 1;
- totsel++;
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->v4) efa->e4->f1++;
- }
- else efa->f= 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->f) {
- CalcCent3f(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) {
- CalcCent3f(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;
- }
-
- /* set first face correct: calc normal */
-
- if(tria_nr==1) {
- CalcNormFloat(startvl->v1->co, startvl->v3->co, startvl->v4->co, nor);
- CalcCent3f(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
- } else {
- CalcNormFloat(startvl->v1->co, startvl->v2->co, startvl->v3->co, nor);
- CalcCent3f(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
- }
- /* first normal is oriented this way or the other */
- if(select) {
- if(select==2) {
- if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipface(startvl);
- }
- else {
- if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
- }
- }
- else if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
-
-
- eed= startvl->e1;
- if(eed->v1==startvl->v1) eed->f= 1;
- else eed->f= 2;
-
- eed= startvl->e2;
- if(eed->v1==startvl->v2) eed->f= 1;
- else eed->f= 2;
-
- eed= startvl->e3;
- if(eed->v1==startvl->v3) eed->f= 1;
- else eed->f= 2;
-
- eed= startvl->e4;
- if(eed) {
- if(eed->v1==startvl->v4) eed->f= 1;
- else eed->f= 2;
- }
-
- startvl->f= 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->f) {
- turn= 0;
- foundone= 0;
-
- ed1= efa->e1;
- ed2= efa->e2;
- ed3= efa->e3;
- ed4= efa->e4;
-
- if(ed1->f) {
- if(ed1->v1==efa->v1 && ed1->f==1) turn= 1;
- if(ed1->v2==efa->v1 && ed1->f==2) turn= 1;
- foundone= 1;
- }
- else if(ed2->f) {
- if(ed2->v1==efa->v2 && ed2->f==1) turn= 1;
- if(ed2->v2==efa->v2 && ed2->f==2) turn= 1;
- foundone= 1;
- }
- else if(ed3->f) {
- if(ed3->v1==efa->v3 && ed3->f==1) turn= 1;
- if(ed3->v2==efa->v3 && ed3->f==2) turn= 1;
- foundone= 1;
- }
- else if(ed4 && ed4->f) {
- if(ed4->v1==efa->v4 && ed4->f==1) turn= 1;
- if(ed4->v2==efa->v4 && ed4->f==2) turn= 1;
- foundone= 1;
- }
-
- if(foundone) {
- found= 1;
- totsel--;
- efa->f= 0;
-
- if(turn) {
- if(ed1->v1==efa->v1) ed1->f= 2;
- else ed1->f= 1;
- if(ed2->v1==efa->v2) ed2->f= 2;
- else ed2->f= 1;
- if(ed3->v1==efa->v3) ed3->f= 2;
- else ed3->f= 1;
- if(ed4) {
- if(ed4->v1==efa->v4) ed4->f= 2;
- else ed4->f= 1;
- }
-
- flipface(efa);
-
- }
- else {
- if(ed1->v1== efa->v1) ed1->f= 1;
- else ed1->f= 2;
- if(ed2->v1==efa->v2) ed2->f= 1;
- else ed2->f= 2;
- if(ed3->v1==efa->v3) ed3->f= 1;
- else ed3->f= 2;
- if(ed4) {
- if(ed4->v1==efa->v4) ed4->f= 1;
- else ed4->f= 2;
- }
- }
- }
- }
- if(direct) efa= efa->next;
- else efa= efa->prev;
- }
- direct= 1-direct;
- }
- }
-
- recalc_editnormals();
-
- makeDispList(G.obedit);
-
- waitcursor(0);
-}
-
-static EditVert *findnearestvert(short sel)
-{
- EditMesh *em = G.editMesh;
- /* if sel==1 the vertices with flag==1 get a disadvantage */
- EditVert *eve,*act=0;
- static EditVert *acto=0;
- short dist=100,temp,mval[2];
-
- if(em->verts.first==0) return 0;
-
- /* do projection */
- calc_meshverts_ext(); /* drawobject.c */
-
- /* we count from acto->next to last, and from first to acto */
- /* does acto exist? */
- eve= em->verts.first;
- while(eve) {
- if(eve==acto) break;
- eve= eve->next;
- }
- if(eve==0) acto= em->verts.first;
-
- if(acto==0) return 0;
-
- /* is there an indicated vertex? part 1 */
- getmouseco_areawin(mval);
- eve= acto->next;
- while(eve) {
- if(eve->h==0) {
- temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys);
- if( (eve->f & 1)==sel ) temp+=5;
- if(temp<dist) {
- act= eve;
- dist= temp;
- if(dist<4) break;
- }
- }
- eve= eve->next;
- }
- /* is there an indicated vertex? part 2 */
- if(dist>3) {
- eve= em->verts.first;
- while(eve) {
- if(eve->h==0) {
- temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys);
- if( (eve->f & 1)==sel ) temp+=5;
- if(temp<dist) {
- act= eve;
- if(temp<4) break;
- dist= temp;
- }
- if(eve== acto) break;
- }
- eve= eve->next;
- }
- }
-
- acto= act;
- return act;
-}
-
-
-static EditEdge *findnearestedge()
-{
- EditMesh *em = G.editMesh;
- EditEdge *closest, *eed;
- EditVert *eve;
- short found=0, mval[2];
- float distance[2], v1[2], v2[2], mval2[2];
-
- if(em->edges.first==0) return NULL;
- else eed=em->edges.first;
-
- /* reset flags */
- for(eve=em->verts.first; eve; eve=eve->next){
- eve->f &= ~2;
- }
-
- calc_meshverts_ext_f2(); /*sets (eve->f & 2) for vertices that aren't visible*/
- getmouseco_areawin(mval);
- closest=NULL;
-
- mval2[0] = (float)mval[0];
- mval2[1] = (float)mval[1];
-
- eed=em->edges.first;
- /*compare the distance to the rest of the edges and find the closest one*/
- while(eed) {
- /* Are both vertices of the edge ofscreen or either of them hidden? then don't select the edge*/
- if( !((eed->v1->f & 2) && (eed->v2->f & 2)) && (eed->v1->h==0 && eed->v2->h==0)){
- v1[0] = eed->v1->xs;
- v1[1] = eed->v1->ys;
- v2[0] = eed->v2->xs;
- v2[1] = eed->v2->ys;
-
- distance[1] = PdistVL2Dfl(mval2, v1, v2);
-
- if(distance[1]<50){
- /*do we have to compare it to other distances? */
- if(found) {
- if (distance[1]<distance[0]){
- distance[0]=distance[1];
- /*save the current closest edge*/
- closest=eed;
- }
- } else {
- distance[0]=distance[1];
- closest=eed;
- found=1;
- }
- }
- }
- eed= eed->next;
- }
-
- /* reset flags */
- for(eve=em->verts.first; eve; eve=eve->next){
- eve->f &= ~2;
- }
-
- if(found) return closest;
- else return 0;
-}
-
-/* does the same as findnearestedge but both vertices of the edge should be on screen*/
-static EditEdge *findnearestvisibleedge()
-{
- EditMesh *em = G.editMesh;
- EditEdge *closest, *eed;
- EditVert *eve;
- short found=0, mval[2];
- float distance[2], v1[2], v2[2], mval2[2];
-
- if(em->edges.first==0) return NULL;
- else eed=em->edges.first;
-
- /* reset flags */
- for(eve=em->verts.first; eve; eve=eve->next){
- eve->f &= ~2;
- }
- calc_meshverts_ext_f2(); /*sets (eve->f & 2) for vertices that aren't visible*/
-
- closest=NULL;
- getmouseco_areawin(mval);
-
- mval2[0] = (float)mval[0]; /* cast to float because of the pdist function only taking floats...*/
- mval2[1] = (float)mval[1];
-
- eed=em->edges.first;
- while(eed) { /* compare the distance to the rest of the edges and find the closest one*/
- if( !((eed->v1->f | eed->v2->f) & 2) && (eed->v1->h==0 && eed->v2->h==0) ){ /* only return edges with both vertices on screen */
- v1[0] = eed->v1->xs;
- v1[1] = eed->v1->ys;
- v2[0] = eed->v2->xs;
- v2[1] = eed->v2->ys;
-
- distance[1] = PdistVL2Dfl(mval2, v1, v2);
-
- if(distance[1]<50){ /* TODO: make this maximum selecting distance selectable (the same with vertice select?) */
- if(found) { /*do we have to compare it to other distances? */
- if (distance[1]<distance[0]){
- distance[0]=distance[1];
- closest=eed; /*save the current closest edge*/
- }
- } else {
- distance[0]=distance[1];
- closest=eed;
- found=1;
- }
- }
- }
- eed= eed->next;
- }
-
- /* reset flags */
- for(eve=em->verts.first; eve; eve=eve->next){
- eve->f &= ~2;
- }
-
- if(found) return closest;
- else return 0;
-}
-
-#if 0
-/* this is a template function to demonstrate a loop with drawing...
- it is a temporal mode, so use with wisdom! if you can avoid, always better. (ton)
-*/
-void loop(int mode)
-{
- EditEdge *eed;
- int mousemove= 1;
-
- while(mousemove) {
- /* uses callback mechanism to draw it all in current area */
- scrarea_do_windraw(curarea);
-
- /* do your stuff */
- eed= findnearestedge();
-
- /* set window matrix to perspective, default an area returns with buttons transform */
- persp(PERSP_VIEW);
- /* make a copy, for safety */
- glPushMatrix();
- /* multiply with the object transformation */
- mymultmatrix(G.obedit->obmat);
-
- /* draw */
- if(eed) {
- glColor3ub(255, 255, 0);
- glBegin(GL_LINES);
- glVertex3fv(eed->v1->co);
- glVertex3fv(eed->v2->co);
- glEnd();
- }
-
- /* restore matrix transform */
- glPopMatrix();
-
- headerprint("We are now in evil edge select mode. Press any key to exit");
-
- /* this also verifies other area/windows for clean swap */
- screen_swapbuffers();
-
- /* testing for user input... */
- while(qtest()) {
- unsigned short val;
- short event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
-
- /* val==0 on key-release event */
- if(val && event!=MOUSEY && event!=MOUSEX) {
- mousemove= 0;
- }
- }
- /* sleep 0.01 second to prevent overload in this poor loop */
- PIL_sleep_ms(10);
-
- }
-
- /* send event to redraw this window, does header too */
- addqueue(curarea->win, REDRAW, 1);
+ countall();
+ me= get_mesh(G.obedit);
+
+ load_editMesh_real(me, 0);
}
-#endif
-
-/*
-functionality: various loop functions
-parameters: mode tells the function what it should do with the loop:
- LOOP_SELECT = select
- LOOP_CUT = cut in half
-*/
-void loopoperations(char mode)
-{
- EditMesh *em = G.editMesh;
- EditVert* look = NULL;
-
- EditEdge *start, *eed, *opposite,*currente, *oldstart;
- EditEdge **tagged = NULL,**taggedsrch = NULL,*close;
-
- EditFace *efa,**percentfacesloop = NULL, *currentvl, *formervl;
-
- short lastface=0, foundedge=0, c=0, tri=0, side=1, totface=0, searching=1, event=0, noface=1;
- short skip,nextpos,percentfaces;
-
- int i=0,ect=0,j=0,k=0,cut,smooth,timesthrough=0,inset = 0;
- float percentcut, outcut;
- char mesg[100];
-
- if ((G.obedit==0) || (em->faces.first==0)) return;
-
- if(mode==LOOP_CUT)undo_push_mesh("Face Loop Subdivide");
- else if(mode==LOOP_SELECT)undo_push_mesh("Select Face Loop");
-
- SetBlenderCursor(BC_VLOOPCURSOR);
-
- start=NULL;
- oldstart=NULL;
-
- while(searching){
-
- /* reset variables */
- start=eed=opposite=currente=0;
- efa=currentvl=formervl=0;
- side=noface=1;
- lastface=foundedge=c=tri=totface=0;
-
- start=findnearestvisibleedge();
-
- /* If the edge doesn't belong to a face, it's not a valid starting edge */
- /* and only accept starting edge if it is part of at least one visible face */
- if(start){
- start->f |= 16;
- efa=em->faces.first;
- while(efa){
- if(efa->e1->f & 16){
- /* since this edge is on the face, check if the face has any hidden verts */
- if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
- noface=0;
- efa->e1->f &= ~16;
- }
- }
- else if(efa->e2->f & 16){
- if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
- noface=0;
- efa->e2->f &= ~16;
- }
- }
- else if(efa->e3->f & 16){
- if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
- noface=0;
- efa->e3->f &= ~16;
- }
- }
- else if(efa->e4 && (efa->e4->f & 16)){
- if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
- noface=0;
- efa->e4->f &= ~16;
- }
- }
-
- efa=efa->next;
- }
- }
-
- /* Did we find anything that is selectable? */
- if(start && !noface && (oldstart==NULL || start!=oldstart)){
-
- /* If we stay in the neighbourhood of this edge, we don't have to recalculate the loop everytime*/
- oldstart=start;
-
- /* Clear flags */
- for(eed=em->edges.first; eed; eed=eed->next){
- eed->f &= ~(2|4|8|32|64);
- eed->v1->f &= ~(2|8|16);
- eed->v2->f &= ~(2|8|16);
- }
-
- for(efa= em->faces.first; efa; efa=efa->next){
- efa->f &= ~(4|8);
- totface++;
- }
-
- /* Tag the starting edge */
- start->f |= (2|4|8|64);
- start->v1->f |= 2;
- start->v2->f |= 2;
-
- currente=start;
-
- /*-----Limit the Search----- */
- while(!lastface && c<totface+1){
-
- /*----------Get Loop------------------------*/
- tri=foundedge=lastface=0;
- efa= em->faces.first;
- while(efa && !foundedge && !tri){
-
- if(!(efa->v4)){ /* Exception for triangular faces */
-
- if((efa->e1->f | efa->e2->f | efa->e3->f) & 2){
- if(!(efa->f & 4)){
- tri=1;
- currentvl=efa;
- if(side==1) efa->f |= 4;
- }
- }
- }
- else{
-
- if((efa->e1->f | efa->e2->f | efa->e3->f | efa->e4->f) & 2){
-
- if(c==0){ /* just pick a face, doesn't matter wich side of the edge we go to */
- if(!(efa->f & 4)){
-
- if(!(efa->e1->v1->f & 2) && !(efa->e1->v2->f & 2)){
- if(efa->e1->v1->h==0 && efa->e1->v2->h==0){
- opposite=efa->e1;
- foundedge=1;
- }
- }
- else if(!(efa->e2->v1->f & 2) && !(efa->e2->v2->f & 2)){
- if(efa->e2->v1->h==0 && efa->e2->v2->h==0){
- opposite=efa->e2;
- foundedge=1;
- }
- }
- else if(!(efa->e3->v1->f & 2) && !(efa->e3->v2->f & 2)){
- if(efa->e3->v1->h==0 && efa->e3->v2->h==0){
- opposite=efa->e3;
- foundedge=1;
- }
- }
- else if(!(efa->e4->v1->f & 2) && !(efa->e4->v2->f & 2)){
- if(efa->e4->v1->h==0 && efa->e4->v2->h==0){
- opposite=efa->e4;
- foundedge=1;
- }
- }
-
- if(foundedge){
- currentvl=efa;
- formervl=efa;
-
- /* mark this side of the edge so we know in which direction we went */
- if(side==1) efa->f |= 4;
- }
- }
- }
- else {
- if(efa!=formervl){ /* prevent going backwards in the loop */
-
- if(!(efa->e1->v1->f & 2) && !(efa->e1->v2->f & 2)){
- if(efa->e1->v1->h==0 && efa->e1->v2->h==0){
- opposite=efa->e1;
- foundedge=1;
- }
- }
- else if(!(efa->e2->v1->f & 2) && !(efa->e2->v2->f & 2)){
- if(efa->e2->v1->h==0 && efa->e2->v2->h==0){
- opposite=efa->e2;
- foundedge=1;
- }
- }
- else if(!(efa->e3->v1->f & 2) && !(efa->e3->v2->f & 2)){
- if(efa->e3->v1->h==0 && efa->e3->v2->h==0){
- opposite=efa->e3;
- foundedge=1;
- }
- }
- else if(!(efa->e4->v1->f & 2) && !(efa->e4->v2->f & 2)){
- if(efa->e4->v1->h==0 && efa->e4->v2->h==0){
- opposite=efa->e4;
- foundedge=1;
- }
- }
-
- currentvl=efa;
- }
- }
- }
- }
- efa=efa->next;
- }
- /*----------END Get Loop------------------------*/
-
-
- /*----------Decisions-----------------------------*/
- if(foundedge){
- /* mark the edge and face as done */
- currente->f |= 8;
- currentvl->f |= 8;
-
- if(opposite->f & 4) lastface=1; /* found the starting edge! close loop */
- else{
- /* un-set the testflags */
- currente->f &= ~2;
- currente->v1->f &= ~2;
- currente->v2->f &= ~2;
-
- /* set the opposite edge to be the current edge */
- currente=opposite;
-
- /* set the current face to be the FORMER face (to prevent going backwards in the loop) */
- formervl=currentvl;
-
- /* set the testflags */
- currente->f |= 2;
- currente->v1->f |= 2;
- currente->v2->f |= 2;
- }
- c++;
- }
- else{
- /* un-set the testflags */
- currente->f &= ~2;
- currente->v1->f &= ~2;
- currente->v2->f &= ~2;
-
- /* mark the edge and face as done */
- currente->f |= 8;
- currentvl->f |= 8;
-
-
-
- /* is the the first time we've ran out of possible faces?
- * try to start from the beginning but in the opposite direction go as far as possible
- */
- if(side==1){
- if(tri)tri=0;
- currente=start;
- currente->f |= 2;
- currente->v1->f |= 2;
- currente->v2->f |= 2;
- side++;
- c=0;
- }
- else lastface=1;
- }
- /*----------END Decisions-----------------------------*/
-
- }
- /*-----END Limit the Search----- */
-
-
- /*------------- Preview lines--------------- */
-
- /* uses callback mechanism to draw it all in current area */
- scrarea_do_windraw(curarea);
-
- /* set window matrix to perspective, default an area returns with buttons transform */
- persp(PERSP_VIEW);
- /* make a copy, for safety */
- glPushMatrix();
- /* multiply with the object transformation */
- mymultmatrix(G.obedit->obmat);
-
- glColor3ub(255, 255, 0);
-
- if(mode==LOOP_SELECT){
- efa= em->faces.first;
- while(efa){
- if(efa->f & 8){
-
- if(!(efa->e1->f & 8)){
- glBegin(GL_LINES);
- glVertex3fv(efa->e1->v1->co);
- glVertex3fv(efa->e1->v2->co);
- glEnd();
- }
-
- if(!(efa->e2->f & 8)){
- glBegin(GL_LINES);
- glVertex3fv(efa->e2->v1->co);
- glVertex3fv(efa->e2->v2->co);
- glEnd();
- }
-
- if(!(efa->e3->f & 8)){
- glBegin(GL_LINES);
- glVertex3fv(efa->e3->v1->co);
- glVertex3fv(efa->e3->v2->co);
- glEnd();
- }
-
- if(efa->e4){
- if(!(efa->e4->f & 8)){
- glBegin(GL_LINES);
- glVertex3fv(efa->e4->v1->co);
- glVertex3fv(efa->e4->v2->co);
- glEnd();
- }
- }
- }
- efa=efa->next;
- }
- }
-
- if(mode==LOOP_CUT){
- efa= em->faces.first;
- while(efa){
- if(efa->f & 8){
- float cen[2][3];
- int a=0;
-
- efa->v1->f &= ~8;
- efa->v2->f &= ~8;
- efa->v3->f &= ~8;
- if(efa->v4)efa->v4->f &= ~8;
-
- if(efa->e1->f & 8){
- cen[a][0]= (efa->e1->v1->co[0] + efa->e1->v2->co[0])/2.0;
- cen[a][1]= (efa->e1->v1->co[1] + efa->e1->v2->co[1])/2.0;
- cen[a][2]= (efa->e1->v1->co[2] + efa->e1->v2->co[2])/2.0;
-
- efa->e1->v1->f |= 8;
- efa->e1->v2->f |= 8;
-
- a++;
- }
- if((efa->e2->f & 8) && a!=2){
- cen[a][0]= (efa->e2->v1->co[0] + efa->e2->v2->co[0])/2.0;
- cen[a][1]= (efa->e2->v1->co[1] + efa->e2->v2->co[1])/2.0;
- cen[a][2]= (efa->e2->v1->co[2] + efa->e2->v2->co[2])/2.0;
-
- efa->e2->v1->f |= 8;
- efa->e2->v2->f |= 8;
-
- a++;
- }
- if((efa->e3->f & 8) && a!=2){
- cen[a][0]= (efa->e3->v1->co[0] + efa->e3->v2->co[0])/2.0;
- cen[a][1]= (efa->e3->v1->co[1] + efa->e3->v2->co[1])/2.0;
- cen[a][2]= (efa->e3->v1->co[2] + efa->e3->v2->co[2])/2.0;
-
- efa->e3->v1->f |= 8;
- efa->e3->v2->f |= 8;
-
- a++;
- }
-
- if(efa->e4){
- if((efa->e4->f & 8) && a!=2){
- cen[a][0]= (efa->e4->v1->co[0] + efa->e4->v2->co[0])/2.0;
- cen[a][1]= (efa->e4->v1->co[1] + efa->e4->v2->co[1])/2.0;
- cen[a][2]= (efa->e4->v1->co[2] + efa->e4->v2->co[2])/2.0;
-
- efa->e4->v1->f |= 8;
- efa->e4->v2->f |= 8;
-
- a++;
- }
- }
- else{ /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
- if(!(efa->v1->f & 8) && efa->v1->h==0){
- cen[a][0]= efa->v1->co[0];
- cen[a][1]= efa->v1->co[1];
- cen[a][2]= efa->v1->co[2];
- a++;
- }
- else if(!(efa->v2->f & 8) && efa->v2->h==0){
- cen[a][0]= efa->v2->co[0];
- cen[a][1]= efa->v2->co[1];
- cen[a][2]= efa->v2->co[2];
- a++;
- }
- else if(!(efa->v3->f & 8) && efa->v3->h==0){
- cen[a][0]= efa->v3->co[0];
- cen[a][1]= efa->v3->co[1];
- cen[a][2]= efa->v3->co[2];
- a++;
- }
- }
-
- if(a==2){
- glBegin(GL_LINES);
-
- glVertex3fv(cen[0]);
- glVertex3fv(cen[1]);
-
- glEnd();
- }
- }
- efa=efa->next;
- }
-
- eed=em->edges.first;
- while(eed){
- if(eed->f & 64){
- glBegin(GL_LINES);
- glColor3ub(200, 255, 200);
- glVertex3fv(eed->v1->co);
- glVertex3fv(eed->v2->co);
- glEnd();
- eed=0;
- }else{
- eed = eed->next;
- }
- }
- }
-
- /* restore matrix transform */
- glPopMatrix();
-
- headerprint("LMB to confirm, RMB to cancel");
-
- /* this also verifies other area/windows for clean swap */
- screen_swapbuffers();
-
- /*--------- END Preview Lines------------*/
-
- }/*if(start!=NULL){ */
-
- while(qtest()) {
- unsigned 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 && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event == MIDDLEMOUSE)){
- searching=0;
- }
- }
-
- }/*while(event!=ESCKEY && event!=RIGHTMOUSE && event!=LEFTMOUSE && event!=RETKEY){*/
-
- /*----------Select Loop------------*/
- if(mode==LOOP_SELECT && start!=NULL && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE || event == BKEY)){
-
- /* If this is a unmodified select, clear the selection */
- if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
- for(efa= em->faces.first;efa;efa=efa->next){
- efa->v1->f &= !1;
- efa->v2->f &= !1;
- efa->v3->f &= !1;
- if(efa->v4)efa->v4->f &= !1;
- }
- }
- /* Alt was not pressed, so add to the selection */
- if(!(G.qual & LR_ALTKEY)){
- for(efa= em->faces.first;efa;efa=efa->next){
- if(efa->f & 8){
- efa->v1->f |= 1;
- efa->v2->f |= 1;
- efa->v3->f |= 1;
- if(efa->v4)efa->v4->f |= 1;
- }
- }
- }
- /* alt was pressed, so subtract from the selection */
- else
- {
- for(efa= em->faces.first;efa;efa=efa->next){
- if(efa->f & 8){
- efa->v1->f &= !1;
- efa->v2->f &= !1;
- efa->v3->f &= !1;
- if(efa->v4)efa->v4->f &= !1;
- }
- }
- }
-
- }
- /*----------END Select Loop------------*/
-
- /*----------Cut Loop---------------*/
- if(mode==LOOP_CUT && start!=NULL && (event==LEFTMOUSE || event==RETKEY)){
-
- /* count the number of edges in the loop */
- for(eed=em->edges.first; eed; eed = eed->next){
- if(eed->f & 8)
- ect++;
- }
-
- tagged = MEM_mallocN(ect*sizeof(EditEdge*), "tagged");
- taggedsrch = MEM_mallocN(ect*sizeof(EditEdge*), "taggedsrch");
- for(i=0;i<ect;i++)
- {
- tagged[i] = NULL;
- taggedsrch[i] = NULL;
- }
- ect = 0;
- for(eed=em->edges.first; eed; eed = eed->next){
- if(eed->f & 8)
- {
- if(eed->h==0){
- eed->v1->f |= 1;
- eed->v2->f |= 1;
- tagged[ect] = eed;
- eed->f &= ~(32);
- ect++;
- }
- }
- }
- taggedsrch[0] = tagged[0];
-
- while(timesthrough < 2)
- {
- i=0;
- while(i < ect){/*Look at the members of the search array to line up cuts*/
- if(taggedsrch[i]==NULL)break;
- for(j=0;j<ect;j++){ /*Look through the list of tagged verts for connected edges*/
- int addededge = 0;
- if(taggedsrch[i]->f & 32) /*If this edgee is marked as flipped, use vert 2*/
- look = taggedsrch[i]->v2;
- else /*else use vert 1*/
- look = taggedsrch[i]->v1;
-
- if(taggedsrch[i] == tagged[j])
- continue; /*If we are looking at the same edge, skip it*/
-
- skip = 0;
- for(k=0;k<ect;k++) {
- if(taggedsrch[k] == NULL) /*go to empty part of search list without finding*/
- break;
- if(tagged[j] == taggedsrch[k]){ /*We found a match already in the list*/
- skip = 1;
- break;
- }
- }
- if(skip)
- continue;
- nextpos = 0;
- if(findedgelist(look,tagged[j]->v2)){
- while(nextpos < ect){ /*Find the first open spot in the search array*/
- if(taggedsrch[nextpos] == NULL){
- taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
- taggedsrch[nextpos]->f |= 32;
- addededge = 1;
- break;
- }
- else
- nextpos++;
- }
- } /* End else if connected to vert 2*/
- else if(findedgelist(look,tagged[j]->v1)){ /*If our vert is connected to vert 1 */
- while(nextpos < ect){ /*Find the first open spot in the search array */
- if(taggedsrch[nextpos] == NULL){
- taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
- addededge = 1;
- break;
- }
- else
- nextpos++;
- }
- }
-
- if(addededge)
- {
- break;
- }
- }/* End Outer For (j)*/
- i++;
- } /* End while(j<ect)*/
- timesthrough++;
- } /*end while timesthrough */
- percentcut = 0.50;
- searching = 1;
- cut = 1;
- smooth = 0;
- close = NULL;
-
-
- /* Count the Number of Faces in the selected loop*/
- percentfaces = 0;
- for(efa= em->faces.first; efa ;efa=efa->next){
- if(efa->f & 8)
- {
- percentfaces++;
- }
- }
-
- /* create a dynamic array for those face pointers */
- percentfacesloop = MEM_mallocN(percentfaces*sizeof(EditFace*), "percentage");
-
- /* put those faces in the array */
- i=0;
- for(efa= em->faces.first; efa ;efa=efa->next){
- if(efa->f & 8)
- {
- percentfacesloop[i] = efa;
- i++;
- }
- }
-
- while(searching){
-
- /* For the % calculation */
- short mval[2];
- float labda, rc[2], len, slen=0.0;
- float v1[2], v2[2], v3[2];
-
- /*------------- Percent Cut Preview Lines--------------- */
- scrarea_do_windraw(curarea);
- persp(PERSP_VIEW);
- glPushMatrix();
- mymultmatrix(G.obedit->obmat);
- glColor3ub(0, 255, 255);
-
- /*Put the preview lines where they should be for the percentage selected.*/
-
- for(i=0;i<percentfaces;i++){
- efa = percentfacesloop[i];
- for(eed = em->edges.first; eed; eed=eed->next){
- if(eed->f & 64){ /* color the starting edge */
- glBegin(GL_LINES);
-
- glColor3ub(200, 255, 200);
- glVertex3fv(eed->v1->co);
- glVertex3fv(eed->v2->co);
-
- glEnd();
-
- glPointSize(5);
- glBegin(GL_POINTS);
- glColor3ub(255,0,255);
-
- if(eed->f & 32)
- glVertex3fv(eed->v2->co);
- else
- glVertex3fv(eed->v1->co);
- glEnd();
-
-
- /*Get Starting Edge Length*/
- slen = sqrt((eed->v1->co[0]-eed->v2->co[0])*(eed->v1->co[0]-eed->v2->co[0])+
- (eed->v1->co[1]-eed->v2->co[1])*(eed->v1->co[1]-eed->v2->co[1])+
- (eed->v1->co[2]-eed->v2->co[2])*(eed->v1->co[2]-eed->v2->co[2]));
- }
- }
-
- if(!inset){
- glColor3ub(0,255,255);
- if(efa->f & 8)
- {
- float cen[2][3];
- int a=0;
-
- efa->v1->f &= ~8;
- efa->v2->f &= ~8;
- efa->v3->f &= ~8;
- if(efa->v4)efa->v4->f &= ~8;
-
- if(efa->e1->f & 8){
- float pct;
- if(efa->e1->f & 32)
- pct = 1-percentcut;
- else
- pct = percentcut;
- cen[a][0]= efa->e1->v1->co[0] - ((efa->e1->v1->co[0] - efa->e1->v2->co[0]) * (pct));
- cen[a][1]= efa->e1->v1->co[1] - ((efa->e1->v1->co[1] - efa->e1->v2->co[1]) * (pct));
- cen[a][2]= efa->e1->v1->co[2] - ((efa->e1->v1->co[2] - efa->e1->v2->co[2]) * (pct));
- efa->e1->v1->f |= 8;
- efa->e1->v2->f |= 8;
- a++;
- }
- if((efa->e2->f & 8) && a!=2)
- {
- float pct;
- if(efa->e2->f & 32)
- pct = 1-percentcut;
- else
- pct = percentcut;
- cen[a][0]= efa->e2->v1->co[0] - ((efa->e2->v1->co[0] - efa->e2->v2->co[0]) * (pct));
- cen[a][1]= efa->e2->v1->co[1] - ((efa->e2->v1->co[1] - efa->e2->v2->co[1]) * (pct));
- cen[a][2]= efa->e2->v1->co[2] - ((efa->e2->v1->co[2] - efa->e2->v2->co[2]) * (pct));
-
- efa->e2->v1->f |= 8;
- efa->e2->v2->f |= 8;
-
- a++;
- }
- if((efa->e3->f & 8) && a!=2){
- float pct;
- if(efa->e3->f & 32)
- pct = 1-percentcut;
- else
- pct = percentcut;
- cen[a][0]= efa->e3->v1->co[0] - ((efa->e3->v1->co[0] - efa->e3->v2->co[0]) * (pct));
- cen[a][1]= efa->e3->v1->co[1] - ((efa->e3->v1->co[1] - efa->e3->v2->co[1]) * (pct));
- cen[a][2]= efa->e3->v1->co[2] - ((efa->e3->v1->co[2] - efa->e3->v2->co[2]) * (pct));
-
- efa->e3->v1->f |= 8;
- efa->e3->v2->f |= 8;
-
- a++;
- }
-
- if(efa->e4){
- if((efa->e4->f & 8) && a!=2){
- float pct;
- if(efa->e4->f & 32)
- pct = 1-percentcut;
- else
- pct = percentcut;
- cen[a][0]= efa->e4->v1->co[0] - ((efa->e4->v1->co[0] - efa->e4->v2->co[0]) * (pct));
- cen[a][1]= efa->e4->v1->co[1] - ((efa->e4->v1->co[1] - efa->e4->v2->co[1]) * (pct));
- cen[a][2]= efa->e4->v1->co[2] - ((efa->e4->v1->co[2] - efa->e4->v2->co[2]) * (pct));
-
- efa->e4->v1->f |= 8;
- efa->e4->v2->f |= 8;
-
- a++;
- }
- }
- else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
- if(!(efa->v1->f & 8) && efa->v1->h==0){
- cen[a][0]= efa->v1->co[0];
- cen[a][1]= efa->v1->co[1];
- cen[a][2]= efa->v1->co[2];
- a++;
- }
- else if(!(efa->v2->f & 8) && efa->v2->h==0){
- cen[a][0]= efa->v2->co[0];
- cen[a][1]= efa->v2->co[1];
- cen[a][2]= efa->v2->co[2];
- a++;
- }
- else if(!(efa->v3->f & 8) && efa->v3->h==0){
- cen[a][0]= efa->v3->co[0];
- cen[a][1]= efa->v3->co[1];
- cen[a][2]= efa->v3->co[2];
- a++;
- }
- }
-
- if(a==2){
- glBegin(GL_LINES);
-
- glVertex3fv(cen[0]);
- glVertex3fv(cen[1]);
-
- glEnd();
- }
- }
- }/* end preview line drawing */
- else{
- glColor3ub(0,128,255);
- if(efa->f & 8)
- {
- float cen[2][3];
- int a=0;
-
- efa->v1->f &= ~8;
- efa->v2->f &= ~8;
- efa->v3->f &= ~8;
- if(efa->v4)efa->v4->f &= ~8;
-
- if(efa->e1->f & 8){
- float nlen,npct;
-
- nlen = sqrt((efa->e1->v1->co[0] - efa->e1->v2->co[0])*(efa->e1->v1->co[0] - efa->e1->v2->co[0])+
- (efa->e1->v1->co[1] - efa->e1->v2->co[1])*(efa->e1->v1->co[1] - efa->e1->v2->co[1])+
- (efa->e1->v1->co[2] - efa->e1->v2->co[2])*(efa->e1->v1->co[2] - efa->e1->v2->co[2]));
- npct = (percentcut*slen)/nlen;
- if(npct >= 1) npct = 1;
- if(efa->e1->f & 32) npct = 1-npct;
-
- cen[a][0]= efa->e1->v1->co[0] - ((efa->e1->v1->co[0] - efa->e1->v2->co[0]) * (npct));
- cen[a][1]= efa->e1->v1->co[1] - ((efa->e1->v1->co[1] - efa->e1->v2->co[1]) * (npct));
- cen[a][2]= efa->e1->v1->co[2] - ((efa->e1->v1->co[2] - efa->e1->v2->co[2]) * (npct));
-
- efa->e1->f1 = 32768*(npct);
- efa->e1->v1->f |= 8;
- efa->e1->v2->f |= 8;
- a++;
- }
- if((efa->e2->f & 8) && a!=2)
- {
- float nlen,npct;
-
- nlen = sqrt((efa->e2->v1->co[0] - efa->e2->v2->co[0])*(efa->e2->v1->co[0] - efa->e2->v2->co[0])+
- (efa->e2->v1->co[1] - efa->e2->v2->co[1])*(efa->e2->v1->co[1] - efa->e2->v2->co[1])+
- (efa->e2->v1->co[2] - efa->e2->v2->co[2])*(efa->e2->v1->co[2] - efa->e2->v2->co[2]));
- npct = (percentcut*slen)/nlen;
- if(npct >= 1) npct = 1;
- if(efa->e2->f & 32) npct = 1-npct;
-
- cen[a][0]= efa->e2->v1->co[0] - ((efa->e2->v1->co[0] - efa->e2->v2->co[0]) * (npct));
- cen[a][1]= efa->e2->v1->co[1] - ((efa->e2->v1->co[1] - efa->e2->v2->co[1]) * (npct));
- cen[a][2]= efa->e2->v1->co[2] - ((efa->e2->v1->co[2] - efa->e2->v2->co[2]) * (npct));
-
- efa->e2->f1 = 32768*(npct);
- efa->e2->v1->f |= 8;
- efa->e2->v2->f |= 8;
- a++;
- }
- if((efa->e3->f & 8) && a!=2){
- float nlen,npct;
-
- nlen = sqrt((efa->e3->v1->co[0] - efa->e3->v2->co[0])*(efa->e3->v1->co[0] - efa->e3->v2->co[0])+
- (efa->e3->v1->co[1] - efa->e3->v2->co[1])*(efa->e3->v1->co[1] - efa->e3->v2->co[1])+
- (efa->e3->v1->co[2] - efa->e3->v2->co[2])*(efa->e3->v1->co[2] - efa->e3->v2->co[2]));
- npct = (percentcut*slen)/nlen;
- if(npct >= 1) npct = 1;
- if(efa->e3->f & 32) npct = 1-npct;
-
- cen[a][0]= efa->e3->v1->co[0] - ((efa->e3->v1->co[0] - efa->e3->v2->co[0]) * (npct));
- cen[a][1]= efa->e3->v1->co[1] - ((efa->e3->v1->co[1] - efa->e3->v2->co[1]) * (npct));
- cen[a][2]= efa->e3->v1->co[2] - ((efa->e3->v1->co[2] - efa->e3->v2->co[2]) * (npct));
-
- efa->e3->f1 = 32768*(npct);
- efa->e3->v1->f |= 8;
- efa->e3->v2->f |= 8;
- a++;
- }
-
- if(efa->e4){
- if((efa->e4->f & 8) && a!=2){
- float nlen,npct;
-
- nlen = sqrt((efa->e4->v1->co[0] - efa->e4->v2->co[0])*(efa->e4->v1->co[0] - efa->e4->v2->co[0])+
- (efa->e4->v1->co[1] - efa->e4->v2->co[1])*(efa->e4->v1->co[1] - efa->e4->v2->co[1])+
- (efa->e4->v1->co[2] - efa->e4->v2->co[2])*(efa->e4->v1->co[2] - efa->e4->v2->co[2]));
- npct = (percentcut*slen)/nlen;
- if(npct >= 1) npct = 1;
- if(efa->e4->f & 32) npct = 1-npct;
-
- cen[a][0]= efa->e4->v1->co[0] - ((efa->e4->v1->co[0] - efa->e4->v2->co[0]) * (npct));
- cen[a][1]= efa->e4->v1->co[1] - ((efa->e4->v1->co[1] - efa->e4->v2->co[1]) * (npct));
- cen[a][2]= efa->e4->v1->co[2] - ((efa->e4->v1->co[2] - efa->e4->v2->co[2]) * (npct));
-
- efa->e4->f1 = 32768*(npct);
- efa->e4->v1->f |= 8;
- efa->e4->v2->f |= 8;
- a++;
- }
- }
- else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
- if(!(efa->v1->f & 8) && efa->v1->h==0){
- cen[a][0]= efa->v1->co[0];
- cen[a][1]= efa->v1->co[1];
- cen[a][2]= efa->v1->co[2];
- a++;
- }
- else if(!(efa->v2->f & 8) && efa->v2->h==0){
- cen[a][0]= efa->v2->co[0];
- cen[a][1]= efa->v2->co[1];
- cen[a][2]= efa->v2->co[2];
- a++;
- }
- else if(!(efa->v3->f & 8) && efa->v3->h==0){
- cen[a][0]= efa->v3->co[0];
- cen[a][1]= efa->v3->co[1];
- cen[a][2]= efa->v3->co[2];
- a++;
- }
- }
-
- if(a==2){
- glBegin(GL_LINES);
-
- glVertex3fv(cen[0]);
- glVertex3fv(cen[1]);
-
- glEnd();
- }
- }
- }
- }
- /* restore matrix transform */
-
- glPopMatrix();
-
- /*--------- END Preview Lines------------*/
- while(qtest())
- {
- unsigned 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 && (event==SKEY))
- {
- if(smooth)smooth = 0;
- else smooth = 1;
- }
-
- if(val && (event==PKEY))
- {
- if(inset)inset = 0;
- else inset = 1;
- }
-
- if(val && (event==FKEY))
- {
- int ct;
- for(ct = 0; ct < ect; ct++){
- if(tagged[ct]->f & 32)
- tagged[ct]->f &= ~32;
- else
- tagged[ct]->f |= 32;
- }
- }
-
- if(val && (event == MIDDLEMOUSE))
- {
- cut = 2;
- searching=0;
- }
- else if(val && (event==LEFTMOUSE || event==RETKEY))
- {
- searching=0;
- }
-
- if(val && (event==ESCKEY || event==RIGHTMOUSE ))
- {
- searching=0;
- cut = 0;
- }
-
- }
-
-
- /* Determine the % on wich the loop should be cut */
- getmouseco_areawin(mval);
- v1[0]=(float)mval[0];
- v1[1]=(float)mval[1];
-
- v2[0]=(float)start->v1->xs;
- v2[1]=(float)start->v1->ys;
-
- v3[0]=(float)start->v2->xs;
- v3[1]=(float)start->v2->ys;
-
- rc[0]= v3[0]-v2[0];
- rc[1]= v3[1]-v2[1];
- len= rc[0]*rc[0]+ rc[1]*rc[1];
-
- labda= ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
-
-
- if(labda<=0.0) labda=0.0;
- else if(labda>=1.0)labda=1.0;
-
- percentcut=labda;
-
- if(start->f & 32)
- percentcut = 1.0-percentcut;
-
- if(cut == 2){
- percentcut = 0.5;
- }
-
- if (G.qual & LR_SHIFTKEY){
-
- percentcut = (int)(percentcut*100.0)/100.0;
- }
- else if (G.qual & LR_CTRLKEY)
- percentcut = (int)(percentcut*10.0)/10.0;
-
- outcut = (percentcut*100.0);
-
- /* Build the Header Line */
-
- if(inset)
- sprintf(mesg,"Cut: %0.2f%% ",slen*percentcut);
- else
- sprintf(mesg,"Cut: %0.2f%% ",outcut);
-
-
- if(smooth)
- sprintf(mesg,"%s| (f)lip side | (s)mooth on |",mesg);
- else
- sprintf(mesg,"%s| (f)lip side | (s)mooth off |",mesg);
-
- if(inset)
- sprintf(mesg,"%s (p)roportional on ",mesg);
- else
- sprintf(mesg,"%s (p)roportional off",mesg);
-
- headerprint(mesg);
-
- screen_swapbuffers();
- }
-
- if(cut){
- /* Now that we have selected a cut %, mark the edges for cutting. */
- if(!inset){
- for(eed = em->edges.first; eed; eed=eed->next){
- if(percentcut == 1.0)
- percentcut = 0.9999;
- else if(percentcut == 0.0)
- percentcut = 0.0001;
- if(eed->f & 8){
- if(eed->f & 32)/* Need to offset by a const. (0.5/32768) for consistant roundoff */
- eed->f1 = 32768*(1.0-percentcut - 0.0000153);
- else
- eed->f1 = 32768*(percentcut + 0.0000153);
- }
- }
- }
- /*-------------------------------------*/
+/* ********************* TOOLS ********************* */
- if(smooth)
- subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD | B_SMOOTH); /* B_KNIFE tells subdivide that edgeflags are already set */
- else
- subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD); /* B_KNIFE tells subdivide that edgeflags are already set */
-
- for(eed = em->edges.first; eed; eed=eed->next){
- if(eed->v1->f & 16) eed->v1->f |= 1;
- else eed->v1->f &= ~1;
-
- if(eed->v2->f & 16) eed->v2->f |= 1;
- else eed->v2->f &= ~1;
- }
- }
- }
- /*----------END Cut Loop-----------------------------*/
-
+
- /* Clear flags */
- for(eed = em->edges.first; eed; eed=eed->next){
- eed->f &= ~(2|4|8|32|64);
- eed->v1->f &= ~(2|16);
- eed->v2->f &= ~(2|16);
- }
-
- for(efa= em->faces.first; efa; efa=efa->next){
- efa->f &= ~(4|8);
- }
-
- countall();
- if(tagged)
- MEM_freeN(tagged);
- if(taggedsrch)
- MEM_freeN(taggedsrch);
- if(percentfacesloop)
- MEM_freeN(percentfacesloop);
-
- /* send event to redraw this window, does header too */
- SetBlenderCursor(SYSCURSOR);
- addqueue(curarea->win, REDRAW, 1);
-}
+/*********************** EDITMESH UNDO ********************************/
+/* Mesh Edit undo by Alexander Ewring, */
+/* ported by Robert Wenzlaff */
+/* */
+/* Any meshedit function wishing to create an undo step, calls */
+/* undo_push_mesh("menu_name_of_step"); */
-void edge_select(void)
+Mesh *undo_new_mesh(void)
{
- EditMesh *em = G.editMesh;
- EditEdge *closest=0;
-
- closest=findnearestedge();
-
- if(closest){ /* Did we find anything that is selectable?*/
-
- if( (G.qual & LR_SHIFTKEY)==0) {
- EditVert *eve;
-
- undo_push_mesh("Select Edge");
- /* deselectall */
- for(eve= em->verts.first; eve; eve= eve->next) eve->f&= ~1;
-
- /* select edge */
- closest->v1->f |= 1;
- closest->v2->f |= 1;
- }
- else {
- /* both of the vertices are selected: deselect both*/
- if((closest->v1->f & 1) && (closest->v2->f & 1) ){
- closest->v1->f &= ~1;
- closest->v2->f &= ~1;
- }
- else {
- /* select both */
- closest->v1->f |= 1;
- closest->v2->f |= 1;
- }
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
- }
+ return(MEM_callocN(sizeof(Mesh), "undo_mesh"));
}
-static void draw_vertices_special(int mode, EditVert *act) /* teken = draw */
+void undo_free_mesh(Mesh *me)
{
- /* (only this view, no other windows) */
- /* hackish routine for visual speed:
- * mode 0: deselect the selected ones, draw them, except act
- * mode 1: only draw act
- */
- EditMesh *em = G.editMesh;
- EditVert *eve;
- float size= BIF_GetThemeValuef(TH_VERTEX_SIZE);
- char col[3];
-
- glPointSize(size);
-
- persp(PERSP_VIEW);
- glPushMatrix();
- mymultmatrix(G.obedit->obmat);
-
- if(mode==0) {
- BIF_ThemeColor(TH_VERTEX);
-
- /* set zbuffer on, its default off outside main drawloops */
- if(G.vd->drawtype > OB_WIRE) {
- G.zbuf= 1;
- glEnable(GL_DEPTH_TEST);
- }
-
- glBegin(GL_POINTS);
- eve= (EditVert *)em->verts.first;
- while(eve) {
- if(eve->h==0) {
- if(eve!=act && (eve->f & 1)) {
- eve->f -= 1;
- glVertex3fv(eve->co);
- }
- }
- eve= eve->next;
- }
- glEnd();
-
- glDisable(GL_DEPTH_TEST);
- G.zbuf= 0;
- }
-
- /* draw active vertex */
- if(act->f & 1) BIF_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
- else BIF_GetThemeColor3ubv(TH_VERTEX, col);
-
- glColor3ub(col[0], col[1], col[2]);
-
- glBegin(GL_POINTS);
- glVertex3fv(act->co);
- glEnd();
-
- glPointSize(1.0);
- glPopMatrix();
-
-
+ if(me->mat) MEM_freeN(me->mat);
+ if(me->orco) MEM_freeN(me->orco);
+ if(me->mvert) MEM_freeN(me->mvert);
+ if(me->medge) MEM_freeN(me->medge);
+ if(me->mface) MEM_freeN(me->mface);
+ if(me->tface) MEM_freeN(me->tface);
+ if(me->dvert) free_dverts(me->dvert, me->totvert);
+ if(me->mcol) MEM_freeN(me->mcol);
+ if(me->msticky) MEM_freeN(me->msticky);
+ if(me->bb) MEM_freeN(me->bb);
+ if(me->disp.first) freedisplist(&me->disp);
+ MEM_freeN(me);
}
-void mouse_mesh(void)
-{
- EditVert *act=0;
- if(G.qual & LR_ALTKEY) {
- if (G.qual & LR_CTRLKEY) edge_select();
- }
- else {
-
- act= findnearestvert(1);
- if(act) {
-
- glDrawBuffer(GL_FRONT);
-
- undo_push_mesh("Select Vertex");
-
- if( (act->f & 1)==0) act->f+= 1;
- else if(G.qual & LR_SHIFTKEY) act->f-= 1;
-
- if((G.qual & LR_SHIFTKEY)==0) {
- draw_vertices_special(0, act);
- }
- else draw_vertices_special(1, act);
-
- countall();
-
- glFlush();
- glDrawBuffer(GL_BACK);
-
- /* signal that frontbuf differs from back */
- curarea->win_swap= WIN_FRONT_OK;
-
- if(G.f & (G_FACESELECT|G_DRAWFACES|G_DRAWEDGES)) {
- /* update full view later on */
- allqueue(REDRAWVIEW3D, 0);
- }
- else allqueue(REDRAWVIEW3D, curarea->win); // all windows except this one
- }
-
- rightmouse_transform();
- }
-}
-
-static void selectconnectedAll(void)
+void undo_push_mesh(char *name)
{
- EditMesh *em = G.editMesh;
- EditVert *v1,*v2;
- EditEdge *eed;
- short flag=1,toggle=0;
-
- if(em->edges.first==0) return;
-
- undo_push_mesh("Select Connected (All)");
+ Mesh *me;
+ int i;
- while(flag==1) {
- flag= 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 & 1) {
- if( (v2->f & 1)==0 ) {
- v2->f |= 1;
- flag= 1;
- }
- }
- else if(v2->f & 1) {
- if( (v1->f & 1)==0 ) {
- v1->f |= 1;
- flag= 1;
- }
- }
- }
- if(toggle & 1) eed= eed->next;
- else eed= eed->prev;
- }
- }
countall();
- allqueue(REDRAWVIEW3D, 0);
-
-}
-
-void selectconnected_mesh(int qual)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve,*v1,*v2,*act= 0;
- EditEdge *eed;
- short flag=1,sel,toggle=0;
-
- if(em->edges.first==0) return;
-
- if(qual & LR_CTRLKEY) {
- selectconnectedAll();
- return;
- }
+ G.undo_edit_level++;
- sel= 3;
- if(qual & LR_SHIFTKEY) sel=2;
-
- act= findnearestvert(sel-2);
- if(act==0) {
- error("Nothing indicated ");
+ if (G.undo_edit_level<0) {
+ printf("undo: ERROR: G.undo_edit_level negative\n");
return;
}
-
- undo_push_mesh("Select Linked");
- /* clear test flags */
- eve= em->verts.first;
- while(eve) {
- eve->f&= ~2;
- eve= eve->next;
- }
- act->f= (act->f & ~3) | sel;
-
- while(flag==1) {
- flag= 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 & 2) {
- if( (v2->f & 2)==0 ) {
- v2->f= (v2->f & ~3) | sel;
- flag= 1;
- }
- }
- else if(v2->f & 2) {
- if( (v1->f & 2)==0 ) {
- v1->f= (v1->f & ~3) | sel;
- flag= 1;
- }
- }
- }
- if(toggle & 1) eed= eed->next;
- else eed= eed->prev;
- }
- }
- countall();
-
- allqueue(REDRAWVIEW3D, 0);
-}
-
-
-short extrudeflag(short flag,short type)
-{
- /* when type=1 old extrusion faces are removed (for spin etc) */
- /* all verts with (flag & 'flag'): extrude */
- /* from old verts, 'flag' is cleared, in new ones it is set */
- EditMesh *em = G.editMesh;
- EditVert *eve, *v1, *v2, *v3, *v4, *nextve;
- EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
- EditFace *efa, *efa2, *nextvl;
- short sel=0, deloud= 0, smooth= 0;
-
- if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
-
- /* clear vert flag f1, we use this to detext 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->f= 1;
- eed->v1->f1= 0;
- eed->v2->f1= 0;
- }
- else eed->f= 0;
-
- eed->f1= 1; /* this indicates it is an 'old' edge (in this routine we make new ones) */
-
- eed= eed->next;
- }
-
- /* we set a flag in all selected faces, and increase the associated edge counters */
-
- efa= em->faces.first;
- while(efa) {
- efa->f= 0;
- if (efa->flag & ME_SMOOTH) {
- if (faceselectedOR(efa, 1)) smooth= 1;
- }
-
- if(faceselectedAND(efa, flag)) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
-
- if(e1->f < 3) e1->f++;
- if(e2->f < 3) e2->f++;
- if(e3->f < 3) e3->f++;
- if(e4 && e4->f < 3) e4->f++;
- efa->f= 1;
- }
- 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;
- }
-
- efa= efa->next;
- }
-
- /* set direction of edges */
- efa= em->faces.first;
- while(efa) {
- if(efa->f== 0) {
- if(efa->e1->f==2) {
- if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
- else efa->e1->dir= 1;
- }
- if(efa->e2->f==2) {
- if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
- else efa->e2->dir= 1;
- }
- if(efa->e3->f==2) {
- if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
- else efa->e3->dir= 1;
- }
- if(efa->e4 && efa->e4->f==2) {
- if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
- else efa->e4->dir= 1;
- }
- }
- efa= efa->next;
- }
-
-
- /* the current state now is:
- eve->f1==1: loose selected vertex
-
- eed->f==0 : edge is not selected, no extrude
- eed->f==1 : edge selected, is not part of a face, extrude
- eed->f==2 : edge selected, is part of 1 face, extrude
- eed->f==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, is not part of a selected face
-
- efa->f==1 : duplicate this face
- */
-
- /* copy all selected vertices, */
- /* write pointer to new vert in old struct at eve->vn */
- eve= em->verts.last;
- while(eve) {
- eve->f&= ~128; /* clear, for later test for loose verts */
- if(eve->f & flag) {
- sel= 1;
- v1= addvertlist(0);
-
- VECCOPY(v1->co, eve->co);
- v1->f= eve->f;
- eve->f-= flag;
- eve->vn= v1;
- }
- else eve->vn= 0;
- eve= eve->prev;
- }
-
- if(sel==0) return 0;
-
- /* all edges with eed->f==1 or eed->f==2 become faces */
- /* if deloud==1 then edges with eed->f>2 are removed */
- eed= em->edges.last;
- while(eed) {
- nexted= eed->prev;
- if( eed->f<3) {
- eed->v1->f|=128; /* = no loose vert! */
- eed->v2->f|=128;
- }
- if( (eed->f==1 || eed->f==2) ) {
- if(eed->f1==2) deloud=1;
-
- if(eed->dir==1) efa2= addfacelist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, NULL);
- else efa2= addfacelist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, NULL);
- if (smooth) efa2->flag |= ME_SMOOTH;
-
- /* 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;
- }
- if(deloud) {
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f==3 && eed->f1==1) {
- remedge(eed);
- free_editedge(eed);
- }
- eed= nexted;
- }
- }
- /* duplicate faces, if necessart remove old ones */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f & 1) {
-
- v1= efa->v1->vn;
- v2= efa->v2->vn;
- v3= efa->v3->vn;
- if(efa->v4) v4= efa->v4->vn; else v4= 0;
-
- efa2= addfacelist(v1, v2, v3, v4, efa);
-
- if(deloud) {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- if (smooth) efa2->flag |= ME_SMOOTH;
- }
- efa= nextvl;
- }
- /* for all vertices with eve->vn!=0
- if eve->f1==1: make edge
- if flag!=128 : if deloud==1: remove
- */
- eve= em->verts.last;
- while(eve) {
- nextve= eve->prev;
- if(eve->vn) {
- if(eve->f1==1) addedgelist(eve, eve->vn, NULL);
- else if( (eve->f & 128)==0) {
- if(deloud) {
- BLI_remlink(&em->verts,eve);
- free_editvert(eve);
- eve= NULL;
- }
- }
- }
- if(eve) eve->f&= ~128;
-
- eve= nextve;
- }
-
- return 1;
-}
-
-void rotateflag(short flag, float *cent, float rotmat[][3])
-{
- /* all verts with (flag & 'flag') rotate */
- EditMesh *em = G.editMesh;
- 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];
- Mat3MulVecfl(rotmat,eve->co);
- eve->co[0]+=cent[0];
- eve->co[1]+=cent[1];
- eve->co[2]+=cent[2];
- }
- eve= eve->next;
- }
-}
-
-void translateflag(short flag, float *vec)
-{
- /* all verts with (flag & 'flag') translate */
- EditMesh *em = G.editMesh;
- 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;
- }
-}
-
-short removedoublesflag(short flag, float limit) /* return amount */
-{
- EditMesh *em = G.editMesh;
- /* all verts with (flag & 'flag') are being evaluated */
- EditVert *eve, *v1, *nextve;
- EditEdge *eed, *e1, *nexted;
- EditFace *efa, *nextvl;
- struct xvertsort *sortblock, *sb, *sb1;
- struct facesort *vlsortblock, *vsb, *vsb1;
- float dist;
- int a, b, test, aantal;
-
- /* flag 128 is cleared, count */
- eve= em->verts.first;
- aantal= 0;
- while(eve) {
- eve->f&= ~128;
- if(eve->f & flag) aantal++;
- eve= eve->next;
- }
- if(aantal==0) return 0;
-
- /* allocate memory and qsort */
- sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- sb->x= eve->co[0]+eve->co[1]+eve->co[2];
- sb->v1= eve;
- sb++;
- }
- eve= eve->next;
- }
- qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco);
-
- /* test for doubles */
- sb= sortblock;
- for(a=0; a<aantal; a++) {
- eve= sb->v1;
- if( (eve->f & 128)==0 ) {
- sb1= sb+1;
- for(b=a+1; b<aantal; b++) {
- /* first test: simpel dist */
- dist= sb1->x - sb->x;
- if(dist > limit) break;
-
- /* second test: is vertex allowed */
- v1= sb1->v1;
- if( (v1->f & 128)==0 ) {
-
- dist= fabs(v1->co[0]-eve->co[0]);
- if(dist<=limit) {
- dist= fabs(v1->co[1]-eve->co[1]);
- if(dist<=limit) {
- dist= fabs(v1->co[2]-eve->co[2]);
- if(dist<=limit) {
- v1->f|= 128;
- v1->vn= eve;
- }
- }
- }
- }
- sb1++;
- }
- }
- sb++;
- }
- MEM_freeN(sortblock);
- /* test edges and insert again */
- eed= em->edges.first;
- while(eed) {
- eed->f= 0;
- eed= eed->next;
- }
- eed= em->edges.last;
- while(eed) {
- nexted= eed->prev;
-
- if(eed->f==0) {
- if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
- remedge(eed);
-
- if(eed->v1->f & 128) eed->v1= eed->v1->vn;
- if(eed->v2->f & 128) eed->v2= eed->v2->vn;
- e1= addedgelist(eed->v1, eed->v2, eed);
-
- if(e1) e1->f= 1;
- if(e1!=eed) free_editedge(eed);
- }
- }
- eed= nexted;
- }
-
- /* first count amount of test faces */
- efa= (struct EditFace *)em->faces.first;
- aantal= 0;
- while(efa) {
- efa->f= 0;
- if(efa->v1->f & 128) efa->f= 1;
- else if(efa->v2->f & 128) efa->f= 1;
- else if(efa->v3->f & 128) efa->f= 1;
- else if(efa->v4 && (efa->v4->f & 128)) efa->f= 1;
-
- if(efa->f==1) aantal++;
- 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->f==1) {
-
- if(efa->v1->f & 128) efa->v1= efa->v1->vn;
- if(efa->v2->f & 128) efa->v2= efa->v2->vn;
- if(efa->v3->f & 128) efa->v3= efa->v3->vn;
- if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->vn;
-
- 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;
- test= 0;
- }
- else if(test==8 || test==16) {
- efa->v4= 0;
- test= 0;
- }
- else {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- aantal--;
- }
- }
- else {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- aantal--;
- }
- }
-
- if(test==0) {
- /* set edge pointers */
- efa->e1= findedgelist(efa->v1, efa->v2);
- efa->e2= findedgelist(efa->v2, efa->v3);
- if(efa->v4==0) {
- efa->e3= findedgelist(efa->v3, efa->v1);
- efa->e4= 0;
- }
- else {
- efa->e3= findedgelist(efa->v3, efa->v4);
- efa->e4= findedgelist(efa->v4, efa->v1);
- }
- }
- }
- efa= nextvl;
- }
-
- /* double faces: sort block */
- /* count again, now all selected faces */
- aantal= 0;
- efa= em->faces.first;
- while(efa) {
- efa->f= 0;
- if(faceselectedAND(efa, 1)) {
- efa->f= 1;
- aantal++;
- }
- efa= efa->next;
- }
-
- if(aantal) {
- /* double faces: sort block */
- vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*aantal, "sortremovedoub");
- efa= em->faces.first;
- while(efa) {
- if(efa->f & 1) {
- if(efa->v4) vsb->x= (long) MIN4( (long)efa->v1, (long)efa->v2, (long)efa->v3, (long)efa->v4);
- else vsb->x= (long) MIN3( (long)efa->v1, (long)efa->v2, (long)efa->v3);
-
- vsb->efa= efa;
- vsb++;
- }
- efa= efa->next;
- }
-
- qsort(vlsortblock, aantal, sizeof(struct facesort), vergface);
-
- vsb= vlsortblock;
- for(a=0; a<aantal; a++) {
- efa= vsb->efa;
- if( (efa->f & 128)==0 ) {
- vsb1= vsb+1;
-
- for(b=a+1; b<aantal; b++) {
-
- /* first test: same pointer? */
- if(vsb->x != vsb1->x) break;
-
- /* second test: is test permitted? */
- efa= vsb1->efa;
- if( (efa->f & 128)==0 ) {
- if( compareface(efa, vsb->efa)) efa->f |= 128;
-
- }
- vsb1++;
- }
- }
- vsb++;
- }
-
- MEM_freeN(vlsortblock);
-
- /* remove double faces */
- efa= (struct EditFace *)em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f & 128) {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- efa= nextvl;
- }
+ if (G.undo_edit[G.undo_edit_level].datablock != 0) {
+ undo_free_mesh(G.undo_edit[G.undo_edit_level].datablock);
}
-
- /* remove double vertices */
- a= 0;
- eve= (struct EditVert *)em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f & flag) {
- if(eve->f & 128) {
- a++;
- BLI_remlink(&em->verts, eve);
- free_editvert(eve);
+ if (strcmp(name, "U")!=0) {
+ for (i=G.undo_edit_level+1; i<(U.undosteps-1); i++) {
+ if (G.undo_edit[i].datablock != 0) {
+ undo_free_mesh(G.undo_edit[i].datablock);
+ G.undo_edit[i].datablock= 0;
}
}
- eve= nextve;
- }
- return a; /* amount */
-}
-
-void xsortvert_flag(int flag)
-{
- EditMesh *em = G.editMesh;
- /* all verts with (flag & 'flag') are sorted */
- EditVert *eve;
- struct xvertsort *sortblock, *sb;
- ListBase tbase;
- int aantal;
-
- /* count */
- eve= em->verts.first;
- aantal= 0;
- while(eve) {
- if(eve->f & flag) aantal++;
- eve= eve->next;
- }
- if(aantal==0) return;
-
- undo_push_mesh("Xsort");
-
- /* allocate memory and sort */
- sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- sb->x= eve->xs;
- sb->v1= eve;
- sb++;
- }
- eve= eve->next;
- }
- qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco);
-
- /* make temporal listbase */
- tbase.first= tbase.last= 0;
- sb= sortblock;
- while(aantal--) {
- eve= sb->v1;
- BLI_remlink(&em->verts, eve);
- BLI_addtail(&tbase, eve);
- sb++;
- }
-
- addlisttolist(&em->verts, &tbase);
-
- MEM_freeN(sortblock);
-}
-
-
-void hashvert_flag(int flag)
-{
- /* switch vertex order using hash table */
- EditMesh *em = G.editMesh;
- EditVert *eve;
- struct xvertsort *sortblock, *sb, onth, *newsort;
- ListBase tbase;
- int aantal, a, b;
-
- /* count */
- eve= em->verts.first;
- aantal= 0;
- while(eve) {
- if(eve->f & flag) aantal++;
- eve= eve->next;
+ G.undo_edit_highest= G.undo_edit_level;
}
- if(aantal==0) return;
-
- undo_push_mesh("Hash");
- /* allocate memory */
- sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- sb->v1= eve;
- sb++;
- }
- eve= eve->next;
- }
+ me= undo_new_mesh();
- BLI_srand(1);
-
- sb= sortblock;
- for(a=0; a<aantal; a++, sb++) {
- b= aantal*BLI_drand();
- if(b>=0 && b<aantal) {
- newsort= sortblock+b;
- onth= *sb;
- *sb= *newsort;
- *newsort= onth;
+ if (G.undo_edit_level>=U.undosteps) {
+ G.undo_edit_level--;
+ undo_free_mesh((Mesh*)G.undo_edit[0].datablock);
+ G.undo_edit[0].datablock= 0;
+ for (i=0; i<(U.undosteps-1); i++) {
+ G.undo_edit[i]= G.undo_edit[i+1];
}
}
- /* make temporal listbase */
- tbase.first= tbase.last= 0;
- sb= sortblock;
- while(aantal--) {
- eve= sb->v1;
- BLI_remlink(&em->verts, eve);
- BLI_addtail(&tbase, eve);
- sb++;
- }
-
- addlisttolist(&em->verts, &tbase);
-
- MEM_freeN(sortblock);
-}
-
-static unsigned int cpack_fact(unsigned int col1, unsigned int col2, float fact)
-{
- char *cp1, *cp2, *cp;
- unsigned int col=0;
- float fact1;
-
- fact1=1-fact; /*result is fact% col1 and (1-fact) % col2 */
-
- cp1= (char *)&col1;
- cp2= (char *)&col2;
- cp= (char *)&col;
-
- cp[0]= fact*cp1[0]+fact1*cp2[0];
- cp[1]= fact*cp1[1]+fact1*cp2[1];
- cp[2]= fact*cp1[2]+fact1*cp2[2];
- cp[3]= fact*cp1[3]+fact1*cp2[3];
-
- return col;
-}
-
-
-static void uv_half(float *uv, float *uv1, float *uv2)
-{
- uv[0]= (uv1[0]+uv2[0])/2.0;
- uv[1]= (uv1[1]+uv2[1])/2.0;
-
-}
-
-static void uv_quart(float *uv, float *uv1)
-{
- uv[0]= (uv1[0]+uv1[2]+uv1[4]+uv1[6])/4.0;
- uv[1]= (uv1[1]+uv1[3]+uv1[5]+uv1[7])/4.0;
-}
-
-static void face_pin_vertex(EditFace *efa, EditVert *vertex)
-{
- if(efa->v1 == vertex) efa->tf.unwrap |= TF_PIN1;
- else if(efa->v2 == vertex) efa->tf.unwrap |= TF_PIN2;
- else if(efa->v3 == vertex) efa->tf.unwrap |= TF_PIN3;
- else if(efa->v4 && vertex && efa->v4 == vertex) efa->tf.unwrap |= TF_PIN4;
-}
-
-static void set_wuv(int tot, EditFace *efa, int v1, int v2, int v3, int v4, EditFace *efapin)
-{
- /* this weird function only to be used for subdivide, the 'w' in the name has no meaning! */
- float *uv, uvo[4][2];
- unsigned int *col, colo[4], col1, col2;
- int a, v;
-
- /* recover pinning */
- if(efapin){
- efa->tf.unwrap= 0;
- if(efapin->tf.unwrap & TF_PIN1) face_pin_vertex(efa, efapin->v1);
- if(efapin->tf.unwrap & TF_PIN2) face_pin_vertex(efa, efapin->v2);
- if(efapin->tf.unwrap & TF_PIN3) face_pin_vertex(efa, efapin->v3);
- if(efapin->tf.unwrap & TF_PIN4) face_pin_vertex(efa, efapin->v4);
- }
-
- /* Numbers corespond to verts (corner points), */
- /* edge->vn's (center edges), the Center */
- memcpy(uvo, efa->tf.uv, sizeof(uvo)); /* And the quincunx points of a face */
- uv= efa->tf.uv[0]; /* as shown here: */
- /* 2 5 1 */
- memcpy(colo, efa->tf.col, sizeof(colo)); /* 10 13 */
- col= efa->tf.col; /* 6 9 8 */
- /* 11 12 */
- if(tot==4) { /* 3 7 4 */
- for(a=0; a<4; a++, uv+=2, col++) {
- if(a==0) v= v1;
- else if(a==1) v= v2;
- else if(a==2) v= v3;
- else v= v4;
-
- if(a==3 && v4==0) break;
-
- if(v<=4) {
- uv[0]= uvo[v-1][0];
- uv[1]= uvo[v-1][1];
- *col= colo[v-1];
- }
- else if(v==8) {
- uv_half(uv, uvo[3], uvo[0]);
- *col= cpack_fact(colo[3], colo[0], 0.5);
- }
- else if(v==9) {
- uv_quart(uv, uvo[0]);
- col1= cpack_fact(colo[1], colo[0], 0.5);
- col2= cpack_fact(colo[2], colo[3], 0.5);
- *col= cpack_fact(col1, col2, 0.5);
- }
- /* Cases for adjacent edge square subdivide Real voodoo */
- /* 1/2 closest corner + 1/4 adjacent corners */
- else if (v==10){ /* case test==3 in subdivideflag() */
- uv[0]=(2*uvo[1][0]+uvo[0][0]+uvo[2][0])/4;
- uv[1]=(2*uvo[1][1]+uvo[0][1]+uvo[2][1])/4;
- col1= cpack_fact(colo[1], colo[0], 0.75);
- col2= cpack_fact(colo[2], colo[3], 0.75);
- *col= cpack_fact(col1, col2, 0.75);
- }
- else if (v==11) { /* case of test==6 */
- uv[0]=(2*uvo[2][0]+uvo[1][0]+uvo[3][0])/4;
- uv[1]=(2*uvo[2][1]+uvo[1][1]+uvo[3][1])/4;
- col1= cpack_fact(colo[1], colo[0], 0.75);
- col2= cpack_fact(colo[2], colo[3], 0.75);
- *col= cpack_fact(col1, col2, 0.25);
- }
- else if (v==12) { /* case of test==12 */
- uv[0]=(2*uvo[3][0]+uvo[2][0]+uvo[0][0])/4;
- uv[1]=(2*uvo[3][1]+uvo[2][1]+uvo[0][1])/4;
- col1= cpack_fact(colo[1], colo[0], 0.25);
- col2= cpack_fact(colo[2], colo[3], 0.25);
- *col= cpack_fact(col1, col2, 0.25);
- }
- else if (v==13) { /* case of test==9 */
- uv[0]=(2*uvo[0][0]+uvo[1][0]+uvo[3][0])/4;
- uv[1]=(2*uvo[0][1]+uvo[1][1]+uvo[3][1])/4;
- col1= cpack_fact(colo[1], colo[0], 0.25);
- col2= cpack_fact(colo[2], colo[3], 0.25);
- *col= cpack_fact(col1, col2, 0.75);
- }
- /* default for consecutive verts*/
- else {
- uv_half(uv, uvo[v-5], uvo[v-4]);
- *col= cpack_fact(colo[v-5], colo[v-4], 0.5);
- }
- }
- }
- else {
- for(a=0; a<3; a++, uv+=2, col++) {
- if(a==0) v= v1;
- else if(a==1) v= v2;
- else v= v3;
-
- if(v<=4) {
- uv[0]= uvo[v-1][0];
- uv[1]= uvo[v-1][1];
- *col= colo[v-1];
- }
- else if(v==7) {
- uv_half(uv, uvo[2], uvo[0]);
- *col= cpack_fact(colo[2], colo[0], 0.5);
- }
- else {
- uv_half(uv, uvo[v-5], uvo[v-4]);
- *col= cpack_fact(colo[v-5], colo[v-4], 0.5);
- }
- }
- }
-}
+ if (strcmp(name, "U")!=0) strcpy(G.undo_edit[G.undo_edit_level].name, name);
+ //printf("undo: saving block: %d [%s]\n", G.undo_edit_level, G.undo_edit[G.undo_edit_level].name);
-static EditVert *vert_from_number(EditFace *efa, int nr)
-{
- switch(nr) {
- case 0:
- return 0;
- case 1:
- return efa->v1;
- case 2:
- return efa->v2;
- case 3:
- return efa->v3;
- case 4:
- return efa->v4;
- case 5:
- return efa->e1->vn;
- case 6:
- return efa->e2->vn;
- case 7:
- return efa->e3->vn;
- case 8:
- return efa->e4->vn;
- }
-
- return NULL;
+ G.undo_edit[G.undo_edit_level].datablock= (void*)me;
+ load_editMesh_real(me, 1);
}
-static void addface_subdiv(EditFace *efa, int val1, int val2, int val3, int val4, EditVert *eve, EditFace *efapin)
+void undo_pop_mesh(int steps) /* steps == 1 is one step */
{
- EditFace *w;
- EditVert *v1, *v2, *v3, *v4;
-
- if(val1>=9) v1= eve;
- else v1= vert_from_number(efa, val1);
-
- if(val2>=9) v2= eve;
- else v2= vert_from_number(efa, val2);
-
- if(val3>=9) v3= eve;
- else v3= vert_from_number(efa, val3);
+ if (G.undo_edit_level > (steps-2)) {
+ undo_push_mesh("U");
+ G.undo_edit_level-= steps;
- if(val4>=9) v4= eve;
- else v4= vert_from_number(efa, val4);
-
- w= addfacelist(v1, v2, v3, v4, efa);
- if(w) {
- if(efa->v4) set_wuv(4, w, val1, val2, val3, val4, efapin);
- else set_wuv(3, w, val1, val2, val3, val4, efapin);
- }
+ //printf("undo: restoring block: %d [%s]\n", G.undo_edit_level, G.undo_edit[G.undo_edit_level].name); -
+ make_editMesh_real((Mesh*)G.undo_edit[G.undo_edit_level].datablock);
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+ G.undo_edit_level--;
+ } else error("No more steps to undo");
}
-static float smoothperc= 0.0;
-
-static void smooth_subdiv_vec(float *v1, float *v2, float *n1, float *n2, float *vec)
-{
- float len, fac, nor[3], nor1[3], nor2[3];
-
- VecSubf(nor, v1, v2);
- len= 0.5*Normalise(nor);
-
- VECCOPY(nor1, n1);
- VECCOPY(nor2, n2);
-
- /* cosine angle */
- fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
-
- vec[0]= fac*nor1[0];
- vec[1]= fac*nor1[1];
- vec[2]= fac*nor1[2];
- /* cosine angle */
- fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
-
- vec[0]+= fac*nor2[0];
- vec[1]+= fac*nor2[1];
- vec[2]+= fac*nor2[2];
-
- vec[0]*= smoothperc*len;
- vec[1]*= smoothperc*len;
- vec[2]*= smoothperc*len;
-}
-
-static void smooth_subdiv_quad(EditFace *efa, float *vec)
+void undo_redo_mesh(void)
{
-
- float nor1[3], nor2[3];
- float vec1[3], vec2[3];
- float cent[3];
-
- /* vlr->e1->vn is new vertex inbetween v1 / v2 */
-
- VecMidf(nor1, efa->v1->no, efa->v2->no);
- Normalise(nor1);
- VecMidf(nor2, efa->v3->no, efa->v4->no);
- Normalise(nor2);
-
- smooth_subdiv_vec( efa->e1->vn->co, efa->e3->vn->co, nor1, nor2, vec1);
-
- VecMidf(nor1, efa->v2->no, efa->v3->no);
- Normalise(nor1);
- VecMidf(nor2, efa->v4->no, efa->v1->no);
- Normalise(nor2);
-
- smooth_subdiv_vec( efa->e2->vn->co, efa->e4->vn->co, nor1, nor2, vec2);
-
- VecAddf(vec1, vec1, vec2);
+ if ( (G.undo_edit[G.undo_edit_level+2].datablock) &&
+ ( (G.undo_edit_level+1) <= G.undo_edit_highest ) ) {
+ G.undo_edit_level++;
- CalcCent4f(cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- VecAddf(vec, cent, vec1);
+ //printf("redo: restoring block: %d [%s]\n", G.undo_edit_level+1, G.undo_edit[G.undo_edit_level+1].name);-
+ make_editMesh_real((Mesh*)G.undo_edit[G.undo_edit_level+1].datablock);
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+ } else error("No more steps to redo");
}
-void subdivideflag(int flag, float rad, int beauty)
+void undo_clear_mesh(void)
{
- EditMesh *em = G.editMesh;
- /* subdivide all with (vertflag & flag) */
- /* if rad>0.0 it's a 'sphere' subdivide */
- /* if rad<0.0 it's a fractal subdivide */
- extern float doublimit;
- EditVert *eve;
- EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
- EditFace *efa, efapin;
- float fac, vec[3], vec1[3], len1, len2, len3, percent;
- short test;
-
- if(beauty & B_SMOOTH) {
- short perc= 100;
-
- if(button(&perc, 10, 500, "Percentage:")==0) return;
-
- smoothperc= 0.292*perc/100.0;
- }
-
- /* edgeflags */
- eed= em->edges.first;
- while((eed) && !(beauty & B_KNIFE)) {
- if( (eed->v1->f & flag) && (eed->v2->f & flag) ) eed->f= flag;
- else eed->f= 0;
- eed= eed->next;
- }
-
- /* if beauty: test for area and clear edge flags of 'ugly' edges */
- if(beauty & B_BEAUTY) {
- efa= em->faces.first;
- while(efa) {
- if( faceselectedAND(efa, flag) ) {
- if(efa->v4) {
-
- /* area */
- len1= AreaQ3Dfl(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- if(len1 <= doublimit) {
- efa->e1->f = 0;
- efa->e2->f = 0;
- efa->e3->f = 0;
- efa->e4->f = 0;
- }
- else {
- len1= VecLenf(efa->v1->co, efa->v2->co) + VecLenf(efa->v3->co, efa->v4->co);
- len2= VecLenf(efa->v2->co, efa->v3->co) + VecLenf(efa->v1->co, efa->v4->co);
-
- if(len1 < len2) {
- efa->e1->f = 0;
- efa->e3->f = 0;
- }
- else if(len1 > len2) {
- efa->e2->f = 0;
- efa->e4->f = 0;
- }
- }
- }
- else {
- /* area */
- len1= AreaT3Dfl(efa->v1->co, efa->v2->co, efa->v3->co);
- if(len1 <= doublimit) {
- efa->e1->f = 0;
- efa->e2->f = 0;
- efa->e3->f = 0;
- }
- else {
- len1= VecLenf(efa->v1->co, efa->v2->co) ;
- len2= VecLenf(efa->v2->co, efa->v3->co) ;
- len3= VecLenf(efa->v3->co, efa->v1->co) ;
-
- if(len1<len2 && len1<len3) {
- efa->e1->f = 0;
- }
- else if(len2<len3 && len2<len1) {
- efa->e2->f = 0;
- }
- else if(len3<len2 && len3<len1) {
- efa->e3->f = 0;
- }
- }
- }
- }
- efa= efa->next;
- }
- }
-
- if(beauty & B_SMOOTH) {
-
- vertexnormals(0); /* no1*/
-
- }
-
- /* make new normal and put in edge, clear flag! needed for face creation part below */
- eed= em->edges.first;
- while(eed) {
- if(eed->f & flag) {
- /* Subdivide percentage is stored in 1/32768ths in eed->f1 */
- if (beauty & B_PERCENTSUBD) percent=(float)(eed->f1)/32768.0;
- else percent=0.5;
-
- vec[0]= (1-percent)*eed->v1->co[0] + percent*eed->v2->co[0];
- vec[1]= (1-percent)*eed->v1->co[1] + percent*eed->v2->co[1];
- vec[2]= (1-percent)*eed->v1->co[2] + percent*eed->v2->co[2];
-
- if(rad > 0.0) { /* subdivide sphere */
- Normalise(vec);
- vec[0]*= rad;
- vec[1]*= rad;
- vec[2]*= rad;
- }
- else if(rad< 0.0) { /* fractal subdivide */
- fac= rad* VecLenf(eed->v1->co, eed->v2->co);
- vec1[0]= fac*BLI_drand();
- vec1[1]= fac*BLI_drand();
- vec1[2]= fac*BLI_drand();
- VecAddf(vec, vec, vec1);
- }
-
- if(beauty & B_SMOOTH) {
- smooth_subdiv_vec(eed->v1->co, eed->v2->co, eed->v1->no, eed->v2->no, vec1);
- VecAddf(vec, vec, vec1);
- }
-
- eed->vn= addvertlist(vec);
- eed->vn->f= eed->v1->f;
-
- }
- else eed->vn= 0;
-
- eed->f= 0; /* needed! */
-
- eed= eed->next;
- }
-
- /* test all faces for subdivide edges, there are 8 or 16 cases (ugh)! */
-
- efa= em->faces.last;
- while(efa) {
-
- efapin= *efa; /* make a copy of efa to recover uv pinning later */
-
- if( faceselectedOR(efa, flag) ) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
-
- test= 0;
- if(e1 && e1->vn) {
- test+= 1;
- e1->f= 1;
- /* add edges here, to copy correct edge data */
- eed= addedgelist(e1->v1, e1->vn, e1);
- eed= addedgelist(e1->vn, e1->v2, e1);
- }
- if(e2 && e2->vn) {
- test+= 2;
- e2->f= 1;
- /* add edges here, to copy correct edge data */
- eed= addedgelist(e2->v1, e2->vn, e2);
- eed= addedgelist(e2->vn, e2->v2, e2);
- }
- if(e3 && e3->vn) {
- test+= 4;
- e3->f= 1;
- /* add edges here, to copy correct edge data */
- eed= addedgelist(e3->v1, e3->vn, e3);
- eed= addedgelist(e3->vn, e3->v2, e3);
- }
- if(e4 && e4->vn) {
- test+= 8;
- e4->f= 1;
- /* add edges here, to copy correct edge data */
- eed= addedgelist(e4->v1, e4->vn, e4);
- eed= addedgelist(e4->vn, e4->v2, e4);
- }
- if(test) {
- if(efa->v4==0) { /* All the permutations of 3 edges*/
- if((test & 3)==3) addface_subdiv(efa, 2, 2+4, 1+4, 0, 0, &efapin);
- if((test & 6)==6) addface_subdiv(efa, 3, 3+4, 2+4, 0, 0, &efapin);
- if((test & 5)==5) addface_subdiv(efa, 1, 1+4, 3+4, 0, 0, &efapin);
-
- if(test==7) { /* four new faces, old face renews */
- efa->v1= e1->vn;
- efa->v2= e2->vn;
- efa->v3= e3->vn;
- set_wuv(3, efa, 1+4, 2+4, 3+4, 0, &efapin);
- }
- else if(test==3) {
- addface_subdiv(efa, 1+4, 2+4, 3, 0, 0, &efapin);
- efa->v2= e1->vn;
- set_wuv(3, efa, 1, 1+4, 3, 0, &efapin);
- }
- else if(test==6) {
- addface_subdiv(efa, 2+4, 3+4, 1, 0, 0, &efapin);
- efa->v3= e2->vn;
- set_wuv(3, efa, 1, 2, 2+4, 0, &efapin);
- }
- else if(test==5) {
- addface_subdiv(efa, 3+4, 1+4, 2, 0, 0, &efapin);
- efa->v1= e3->vn;
- set_wuv(3, efa, 3+4, 2, 3, 0, &efapin);
- }
- else if(test==1) {
- addface_subdiv(efa, 1+4, 2, 3, 0, 0, &efapin);
- efa->v2= e1->vn;
- set_wuv(3, efa, 1, 1+4, 3, 0, &efapin);
- }
- else if(test==2) {
- addface_subdiv(efa, 2+4, 3, 1, 0, 0, &efapin);
- efa->v3= e2->vn;
- set_wuv(3, efa, 1, 2, 2+4, 0, &efapin);
- }
- else if(test==4) {
- addface_subdiv(efa, 3+4, 1, 2, 0, 0, &efapin);
- efa->v1= e3->vn;
- set_wuv(3, efa, 3+4, 2, 3, 0, &efapin);
- }
- efa->e1= addedgelist(efa->v1, efa->v2, NULL);
- efa->e2= addedgelist(efa->v2, efa->v3, NULL);
- efa->e3= addedgelist(efa->v3, efa->v1, NULL);
-
- }
- else { /* All the permutations of 4 faces */
- if(test==15) {
- /* add a new point in center */
- CalcCent4f(vec, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
-
- if(beauty & B_SMOOTH) {
- smooth_subdiv_quad(efa, vec); /* adds */
- }
- eve= addvertlist(vec);
-
- eve->f |= flag;
-
- addface_subdiv(efa, 2, 2+4, 9, 1+4, eve, &efapin);
- addface_subdiv(efa, 3, 3+4, 9, 2+4, eve, &efapin);
- addface_subdiv(efa, 4, 4+4, 9, 3+4, eve, &efapin);
-
- efa->v2= e1->vn;
- efa->v3= eve;
- efa->v4= e4->vn;
- set_wuv(4, efa, 1, 1+4, 9, 4+4, &efapin);
- }
- else {
- if(((test & 3)==3)&&(test!=3)) addface_subdiv(efa, 1+4, 2, 2+4, 0, 0, &efapin);
- if(((test & 6)==6)&&(test!=6)) addface_subdiv(efa, 2+4, 3, 3+4, 0, 0, &efapin);
- if(((test & 12)==12)&&(test!=12)) addface_subdiv(efa, 3+4, 4, 4+4, 0, 0, &efapin);
- if(((test & 9)==9)&&(test!=9)) addface_subdiv(efa, 4+4, 1, 1+4, 0, 0, &efapin);
-
- if(test==1) { /* Edge 1 has new vert */
- addface_subdiv(efa, 1+4, 2, 3, 0, 0, &efapin);
- addface_subdiv(efa, 1+4, 3, 4, 0, 0, &efapin);
- efa->v2= e1->vn;
- efa->v3= efa->v4;
- efa->v4= 0;
- set_wuv(4, efa, 1, 1+4, 4, 0, &efapin);
- }
- else if(test==2) { /* Edge 2 has new vert */
- addface_subdiv(efa, 2+4, 3, 4, 0, 0, &efapin);
- addface_subdiv(efa, 2+4, 4, 1, 0, 0, &efapin);
- efa->v3= e2->vn;
- efa->v4= 0;
- set_wuv(4, efa, 1, 2, 2+4, 0, &efapin);
- }
- else if(test==4) { /* Edge 3 has new vert */
- addface_subdiv(efa, 3+4, 4, 1, 0, 0, &efapin);
- addface_subdiv(efa, 3+4, 1, 2, 0, 0, &efapin);
- efa->v1= efa->v2;
- efa->v2= efa->v3;
- efa->v3= e3->vn;
- efa->v4= 0;
- set_wuv(4, efa, 2, 3, 3+4, 0, &efapin);
- }
- else if(test==8) { /* Edge 4 has new vert */
- addface_subdiv(efa, 4+4, 1, 2, 0, 0, &efapin);
- addface_subdiv(efa, 4+4, 2, 3, 0, 0, &efapin);
- efa->v1= efa->v3;
- efa->v2= efa->v4;
- efa->v3= e4->vn;
- efa->v4= 0;
- set_wuv(4, efa, 3, 4, 4+4, 0, &efapin);
- }
- else if(test==3) { /*edge 1&2 */
- /* make new vert in center of new edge */
- vec[0]=(e1->vn->co[0]+e2->vn->co[0])/2;
- vec[1]=(e1->vn->co[1]+e2->vn->co[1])/2;
- vec[2]=(e1->vn->co[2]+e2->vn->co[2])/2;
- eve= addvertlist(vec);
- eve->f |= flag;
- /* Add new faces */
- addface_subdiv(efa, 4, 10, 2+4, 3, eve, &efapin);
- addface_subdiv(efa, 4, 1, 1+4, 10, eve, &efapin);
- /* orig face becomes small corner */
- efa->v1=e1->vn;
- //efa->v2=efa->v2;
- efa->v3=e2->vn;
- efa->v4=eve;
-
- set_wuv(4, efa, 1+4, 2, 2+4, 10, &efapin);
- }
- else if(test==6) { /* 2&3 */
- /* make new vert in center of new edge */
- vec[0]=(e2->vn->co[0]+e3->vn->co[0])/2;
- vec[1]=(e2->vn->co[1]+e3->vn->co[1])/2;
- vec[2]=(e2->vn->co[2]+e3->vn->co[2])/2;
- eve= addvertlist(vec);
- eve->f |= flag;
- /*New faces*/
- addface_subdiv(efa, 1, 11, 3+4, 4, eve, &efapin);
- addface_subdiv(efa, 1, 2, 2+4, 11, eve, &efapin);
- /* orig face becomes small corner */
- efa->v1=e2->vn;
- efa->v2=efa->v3;
- efa->v3=e3->vn;
- efa->v4=eve;
-
- set_wuv(4, efa, 2+4, 3, 3+4, 11, &efapin);
- }
- else if(test==12) { /* 3&4 */
- /* make new vert in center of new edge */
- vec[0]=(e3->vn->co[0]+e4->vn->co[0])/2;
- vec[1]=(e3->vn->co[1]+e4->vn->co[1])/2;
- vec[2]=(e3->vn->co[2]+e4->vn->co[2])/2;
- eve= addvertlist(vec);
- eve->f |= flag;
- /*New Faces*/
- addface_subdiv(efa, 2, 12, 4+4, 1, eve, &efapin);
- addface_subdiv(efa, 2, 3, 3+4, 12, eve, &efapin);
- /* orig face becomes small corner */
- efa->v1=e3->vn;
- efa->v2=efa->v4;
- efa->v3=e4->vn;
- efa->v4=eve;
-
- set_wuv(4, efa, 3+4, 4, 4+4, 12, &efapin);
- }
- else if(test==9) { /* 4&1 */
- /* make new vert in center of new edge */
- vec[0]=(e1->vn->co[0]+e4->vn->co[0])/2;
- vec[1]=(e1->vn->co[1]+e4->vn->co[1])/2;
- vec[2]=(e1->vn->co[2]+e4->vn->co[2])/2;
- eve= addvertlist(vec);
- eve->f |= flag;
- /*New Faces*/
- addface_subdiv(efa, 3, 13, 1+4, 2, eve, &efapin);
- addface_subdiv(efa, 3, 4, 4+4,13, eve, &efapin);
- /* orig face becomes small corner */
- efa->v2=efa->v1;
- efa->v1=e4->vn;
- efa->v3=e1->vn;
- efa->v4=eve;
-
- set_wuv(4, efa, 4+4, 1, 1+4, 13, &efapin);
- }
- else if(test==5) { /* 1&3 */
- addface_subdiv(efa, 1+4, 2, 3, 3+4, 0, &efapin);
- efa->v2= e1->vn;
- efa->v3= e3->vn;
- set_wuv(4, efa, 1, 1+4, 3+4, 4, &efapin);
- }
- else if(test==10) { /* 2&4 */
- addface_subdiv(efa, 2+4, 3, 4, 4+4, 0, &efapin);
- efa->v3= e2->vn;
- efa->v4= e4->vn;
- set_wuv(4, efa, 1, 2, 2+4, 4+4, &efapin);
- }/* Unfortunately, there is no way to avoid tris on 1 or 3 edges*/
- else if(test==7) { /*1,2&3 */
- addface_subdiv(efa, 1+4, 2+4, 3+4, 0, 0, &efapin);
- efa->v2= e1->vn;
- efa->v3= e3->vn;
- set_wuv(4, efa, 1, 1+4, 3+4, 4, &efapin);
- }
-
- else if(test==14) { /* 2,3&4 */
- addface_subdiv(efa, 2+4, 3+4, 4+4, 0, 0, &efapin);
- efa->v3= e2->vn;
- efa->v4= e4->vn;
- set_wuv(4, efa, 1, 2, 2+4, 4+4, &efapin);
- }
- else if(test==13) {/* 1,3&4 */
- addface_subdiv(efa, 3+4, 4+4, 1+4, 0, 0, &efapin);
- efa->v4= e3->vn;
- efa->v1= e1->vn;
- set_wuv(4, efa, 1+4, 3, 3, 3+4, &efapin);
- }
- else if(test==11) { /* 1,2,&4 */
- addface_subdiv(efa, 4+4, 1+4, 2+4, 0, 0, &efapin);
- efa->v1= e4->vn;
- efa->v2= e2->vn;
- set_wuv(4, efa, 4+4, 2+4, 3, 4, &efapin);
- }
- }
- efa->e1= addedgelist(efa->v1, efa->v2, NULL);
- efa->e2= addedgelist(efa->v2, efa->v3, NULL);
- if(efa->v4) efa->e3= addedgelist(efa->v3, efa->v4, NULL);
- else efa->e3= addedgelist(efa->v3, efa->v1, NULL);
- if(efa->v4) efa->e4= addedgelist(efa->v4, efa->v1, NULL);
- else efa->e4= NULL;
- }
- }
- }
- efa= efa->prev;
- }
+ int i;
+ Mesh *me;
- /* remove all old edges, if needed make new ones */
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if( eed->vn ) {
- eed->vn->f |= 16;
- if(eed->f==0) { /* not used in face */
- addedgelist(eed->v1, eed->vn, eed);
- addedgelist(eed->vn, eed->v2, eed);
- }
- remedge(eed);
- free_editedge(eed);
+ for (i=0; i<=UNDO_EDIT_MAX; i++) {
+ me= (Mesh*) G.undo_edit[i].datablock;
+ if (me) {
+ //printf("undo: freeing %d\n", i);
+ undo_free_mesh(me);
+ G.undo_edit[i].datablock= 0;
}
- eed= nexted;
}
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
}
-void adduplicateflag(int flag)
-{
- EditMesh *em = G.editMesh;
- /* old verts have flag 128 set, and flag 'flag' cleared
- new verts have flag 'flag' set */
- EditVert *eve, *v1, *v2, *v3, *v4;
- EditEdge *eed;
- EditFace *efa;
-
- /* vertices first */
- eve= em->verts.last;
- while(eve) {
- eve->f&= ~128;
- if(eve->f & flag) {
- v1= addvertlist(eve->co);
- v1->f= eve->f;
- eve->f-= flag;
- eve->f|= 128;
- eve->vn= v1;
-#ifdef __NLA
- /* >>>>> FIXME: Copy deformation weight ? */
- v1->totweight = eve->totweight;
- if (eve->totweight){
- v1->dw = MEM_mallocN (eve->totweight * sizeof(MDeformWeight), "deformWeight");
- memcpy (v1->dw, eve->dw, eve->totweight * sizeof(MDeformWeight));
- }
- else
- v1->dw=NULL;
+#ifdef WIN32
+ #ifndef snprintf
+ #define snprintf _snprintf
+ #endif
#endif
- }
- eve= eve->prev;
- }
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & 128) && (eed->v2->f & 128) ) {
- v1= eed->v1->vn;
- v2= eed->v2->vn;
- addedgelist(v1, v2, eed);
- }
- eed= eed->next;
- }
- /* then dupicate faces */
- efa= em->faces.first;
- while(efa) {
- if( (efa->v1->f & 128) && (efa->v2->f & 128) && (efa->v3->f & 128) ) {
- if(efa->v4) {
- if(efa->v4->f & 128) {
- v1= efa->v1->vn;
- v2= efa->v2->vn;
- v3= efa->v3->vn;
- v4= efa->v4->vn;
- addfacelist(v1, v2, v3, v4, efa);
- }
- }
- else {
- v1= efa->v1->vn;
- v2= efa->v2->vn;
- v3= efa->v3->vn;
- addfacelist(v1, v2, v3, 0, efa);
- }
- }
- efa= efa->next;
- }
-}
-
-static void delfaceflag(int flag)
-{
- EditMesh *em = G.editMesh;
- /* delete all faces with 'flag', including edges and loose vertices */
- /* in vertices the 'flag' is cleared */
- EditVert *eve,*nextve;
- EditEdge *eed, *nexted;
- EditFace *efa,*nextvl;
-
- eed= em->edges.first;
- while(eed) {
- eed->f= 0;
- eed= eed->next;
- }
-
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(faceselectedAND(efa, flag)) {
-
- efa->e1->f= 1;
- efa->e2->f= 1;
- efa->e3->f= 1;
- if(efa->e4) {
- efa->e4->f= 1;
- }
-
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- efa= nextvl;
- }
- /* all faces with 1, 2 (3) vertices selected: make sure we keep the edges */
- efa= em->faces.first;
- while(efa) {
- efa->e1->f= 0;
- efa->e2->f= 0;
- efa->e3->f= 0;
- if(efa->e4) {
- efa->e4->f= 0;
- }
-
- efa= efa->next;
- }
-
- /* test all edges for vertices with 'flag', and clear */
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f==1) {
- remedge(eed);
- free_editedge(eed);
- }
- else if( (eed->v1->f & flag) || (eed->v2->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(eve);
- }
- eve= nextve;
- }
-
-}
-
-void extrude_mesh(void)
+void undo_menu_mesh(void)
{
- short a;
+ short event=66;
+ int i;
+ char menu[2080], temp[64];
TEST_EDITMESH
- if(okee("Extrude")==0) return;
-
- waitcursor(1);
- undo_push_mesh("Extrude");
+ strcpy(menu, "Undo %t|%l");
+ strcat(menu, "|All changes%x1|%l");
- a= extrudeflag(1,1);
- waitcursor(0);
- if(a==0) {
- error("No valid vertices are selected");
- }
- else {
- countall(); /* for G.totvert in calc_meshverts() */
- calc_meshverts();
- transform('d');
- G.undo_edit_level--; /* to hide the transform from undo */
+ for (i=G.undo_edit_level; i>=0; i--) {
+ snprintf(temp, 64, "|%s%%x%d", G.undo_edit[i].name, i+2);
+ strcat(menu, temp);
}
-}
-
-void adduplicate_mesh(void)
-{
+ event=pupmenu_col(menu, 20);
- TEST_EDITMESH
+ if(event<1) return;
- waitcursor(1);
- undo_push_mesh("Duplicate");
- adduplicateflag(1);
- waitcursor(0);
- countall(); /* for G.totvert in calc_meshverts() */
- transform('d');
+ if (event==1) remake_editMesh();
+ else undo_pop_mesh(G.undo_edit_level-event+3);
}
-void split_mesh(void)
-{
-
- TEST_EDITMESH
-
- if(okee(" Split ")==0) return;
-
- waitcursor(1);
- undo_push_mesh("Split");
- /* make duplicate first */
- adduplicateflag(1);
- /* old faces have 3x flag 128 set, delete them */
- delfaceflag(128);
-
- waitcursor(0);
+/* *************** END UNDO *************/
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
+/* *************** SEPARATE (partial exit editmode) *************/
void separatemenu(void)
@@ -5405,4815 +1690,3 @@ void separate_mesh_loose(void)
}
-void extrude_repeat_mesh(int steps, float offs)
-{
- float dvec[3], tmat[3][3], bmat[3][3];
- short a,ok;
-
- TEST_EDITMESH
- waitcursor(1);
-
- undo_push_mesh("Extrude Repeat");
-
- /* dvec */
- dvec[0]= G.vd->persinv[2][0];
- dvec[1]= G.vd->persinv[2][1];
- dvec[2]= G.vd->persinv[2][2];
- Normalise(dvec);
- dvec[0]*= offs;
- dvec[1]*= offs;
- dvec[2]*= offs;
-
- /* base correction */
- Mat3CpyMat4(bmat, G.obedit->obmat);
- Mat3Inv(tmat, bmat);
- Mat3MulVecfl(tmat, dvec);
-
- for(a=0;a<steps;a++) {
- ok= extrudeflag(1,1);
- if(ok==0) {
- error("No valid vertices are selected");
- break;
- }
- translateflag(1, dvec);
- }
-
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
- waitcursor(0);
-}
-
-void spin_mesh(int steps,int degr,float *dvec, int mode)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve,*nextve;
- float *curs, 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;
-
- TEST_EDITMESH
-
- waitcursor(1);
-
- undo_push_mesh("Spin");
-
- /* imat and centre and size */
- Mat3CpyMat4(bmat, G.obedit->obmat);
- Mat3Inv(imat,bmat);
-
- curs= give_cursor();
- VECCOPY(cent, curs);
- cent[0]-= G.obedit->obmat[3][0];
- cent[1]-= G.obedit->obmat[3][1];
- cent[2]-= G.obedit->obmat[3][2];
- Mat3MulVecfl(imat, cent);
-
- phi= degr*M_PI/360.0;
- phi/= steps;
- if(editbutflag & B_CLOCKWISE) phi= -phi;
-
- if(dvec) {
- n[0]=n[1]= 0.0;
- n[2]= 1.0;
- } else {
- n[0]= G.vd->viewinv[2][0];
- n[1]= G.vd->viewinv[2][1];
- n[2]= G.vd->viewinv[2][2];
- Normalise(n);
- }
-
- q[0]= cos(phi);
- si= sin(phi);
- q[1]= n[0]*si;
- q[2]= n[1]*si;
- q[3]= n[2]*si;
- QuatToMat3(q, cmat);
-
- Mat3MulMat3(tmat,cmat,bmat);
- Mat3MulMat3(bmat,imat,tmat);
-
- if(mode==0) if(editbutflag & B_KEEPORIG) adduplicateflag(1);
- ok= 1;
-
- for(a=0;a<steps;a++) {
- if(mode==0) ok= extrudeflag(1,1);
- else adduplicateflag(1);
- if(ok==0) {
- error("No valid vertices are selected");
- break;
- }
- rotateflag(1, cent, bmat);
- if(dvec) {
- Mat3MulVecfl(bmat,dvec);
- translateflag(1,dvec);
- }
- }
-
- waitcursor(0);
- if(ok==0) {
- /* no vertices or only loose ones selected, remove duplicates */
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f & 1) {
- BLI_remlink(&em->verts,eve);
- free_editvert(eve);
- }
- eve= nextve;
- }
- }
- countall();
- recalc_editnormals();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-void screw_mesh(int steps,int turns)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve,*v1=0,*v2=0;
- EditEdge *eed;
- float dvec[3], nor[3];
-
- TEST_EDITMESH
-
- /* first condition: we need frontview! */
- if(G.vd->view!=1) {
- error("Must be in Front View");
- return;
- }
-
- undo_push_mesh("Screw");
-
- /* clear flags */
- eve= em->verts.first;
- while(eve) {
- eve->f1= 0;
- eve= eve->next;
- }
- /* edges set flags in verts */
- eed= em->edges.first;
- while(eed) {
- if(eed->v1->f & 1) {
- if(eed->v2->f & 1) {
- /* watch: f1 is a byte */
- if(eed->v1->f1<2) eed->v1->f1++;
- if(eed->v2->f1<2) eed->v2->f1++;
- }
- }
- eed= eed->next;
- }
- /* find two vertices with eve->f1==1, more or less is wrong */
- eve= em->verts.first;
- while(eve) {
- if(eve->f1==1) {
- if(v1==0) v1= eve;
- else if(v2==0) v2= eve;
- else {
- v1=0;
- break;
- }
- }
- eve= eve->next;
- }
- if(v1==0 || v2==0) {
- error("No curve is selected");
- return;
- }
-
- /* 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, G.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];
- }
-
- spin_mesh(turns*steps, turns*360, dvec, 0);
-
-}
-
-void selectswap_mesh(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
-
- eve= em->verts.first;
- while(eve) {
- if(eve->h==0) {
- if(eve->f & 1) eve->f&= ~1;
- else eve->f|= 1;
- }
- eve= eve->next;
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
-
-}
-
-/* ******************************* ADD ********************* */
-
-void addvert_mesh(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve,*v1=0;
- float *curs, mat[3][3],imat[3][3];
-
- TEST_EDITMESH
-
- Mat3CpyMat4(mat, G.obedit->obmat);
- Mat3Inv(imat, mat);
-
- v1= em->verts.first;
- while(v1) {
- if(v1->f & 1) break;
- v1= v1->next;
- }
- eve= v1; /* prevent there are more selected */
- while(eve) {
- eve->f&= ~1;
- eve= eve->next;
- }
-
- eve= addvertlist(0);
-
- curs= give_cursor();
- VECCOPY(eve->co, curs);
- eve->xs= G.vd->mx;
- eve->ys= G.vd->my;
- VecSubf(eve->co, eve->co, G.obedit->obmat[3]);
-
- Mat3MulVecfl(imat, eve->co);
- eve->f= 1;
-
- if(v1) {
- addedgelist(v1, eve, NULL);
- v1->f= 0;
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-
- while(get_mbut()&R_MOUSE);
-
-}
-
-void addedgeface_mesh(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve, *neweve[4];
- EditFace *efa;
- float con1, con2, con3;
- short aantal=0;
-
- if( (G.vd->lay & G.obedit->lay)==0 ) return;
-
- /* how many selected ? */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- aantal++;
- if(aantal>4) break;
- neweve[aantal-1]= eve;
- }
- eve= eve->next;
- }
- if(aantal==2) {
- addedgelist(neweve[0], neweve[1], NULL);
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
- return;
- }
- if(aantal<2 || aantal>4) {
- error("Incorrect number of vertices to make edge/face");
- return;
- }
-
- efa= NULL; // check later
-
- if(aantal==3) {
- if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0) {
-
- efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, NULL);
-
- }
- else error("The selected vertices already form a face");
- }
- else if(aantal==4) {
- if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
-
- con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co);
- con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co);
- con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co);
-
- if(con1>=con2 && con1>=con3)
- efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL);
- else if(con2>=con1 && con2>=con3)
- efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL);
- else
- efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL);
-
- }
- else error("The selected vertices already form a face");
- }
-
- if(efa) { // now we're calculating direction of normal
- float inp;
- /* dot product view mat with normal, should give info! */
-
- CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
-
- inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
-
- if(inp < 0.0) flipface(efa);
- }
-
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-static void erase_edges(ListBase *l)
-{
- EditEdge *ed, *nexted;
-
- ed = (EditEdge *) l->first;
- while(ed) {
- nexted= ed->next;
- if( (ed->v1->f & 1) || (ed->v2->f & 1) ) {
- remedge(ed);
- free_editedge(ed);
- }
- ed= nexted;
- }
-}
-
-static void erase_faces(ListBase *l)
-{
- EditFace *f, *nextf;
-
- f = (EditFace *) l->first;
-
- while(f) {
- nextf= f->next;
- if( faceselectedOR(f, 1) ) {
- BLI_remlink(l, f);
- free_editface(f);
- }
- f = nextf;
- }
-}
-
-static void erase_vertices(ListBase *l)
-{
- EditVert *v, *nextv;
-
- v = (EditVert *) l->first;
- while(v) {
- nextv= v->next;
- if(v->f & 1) {
- BLI_remlink(l, v);
- free_editvert(v);
- }
- v = nextv;
- }
-}
-
-void delete_mesh(void)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa, *nextvl;
- EditVert *eve,*nextve;
- EditEdge *eed,*nexted;
- short event;
- int count;
-
- TEST_EDITMESH
-
- event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5");
- if(event<1) return;
-
- if(event==10 ) {
- undo_push_mesh("Erase Vertices");
- erase_edges(&em->edges);
- erase_faces(&em->faces);
- erase_vertices(&em->verts);
- }
- else if(event==4) {
- undo_push_mesh("Erase Edges & Faces");
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- /* delete only faces with 2 or more vertices selected */
- count= 0;
- if(efa->v1->f & 1) count++;
- if(efa->v2->f & 1) count++;
- if(efa->v3->f & 1) count++;
- if(efa->v4 && (efa->v4->f & 1)) count++;
- if(count>1) {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- efa= nextvl;
- }
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
- remedge(eed);
- free_editedge(eed);
- }
- eed= nexted;
- }
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- event=0;
- if( efa->v1->f & 1) event++;
- if( efa->v2->f & 1) event++;
- if( efa->v3->f & 1) event++;
- if(efa->v4 && (efa->v4->f & 1)) event++;
-
- if(event>1) {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- efa= nextvl;
- }
- }
- else if(event==1) {
- undo_push_mesh("Erase Edges");
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
- remedge(eed);
- free_editedge(eed);
- }
- eed= nexted;
- }
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- event=0;
- if( efa->v1->f & 1) event++;
- if( efa->v2->f & 1) event++;
- if( efa->v3->f & 1) event++;
- if(efa->v4 && (efa->v4->f & 1)) event++;
-
- if(event>1) {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- efa= nextvl;
- }
- /* to remove loose vertices: */
- eed= em->edges.first;
- while(eed) {
- if( eed->v1->f & 1) eed->v1->f-=1;
- if( eed->v2->f & 1) eed->v2->f-=1;
- eed= eed->next;
- }
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f & 1) {
- BLI_remlink(&em->verts,eve);
- free_editvert(eve);
- }
- eve= nextve;
- }
-
- }
- else if(event==2) {
- undo_push_mesh("Erase Faces");
- delfaceflag(1);
- }
- else if(event==3) {
- undo_push_mesh("Erase All");
- if(em->verts.first) free_vertlist(&em->verts);
- if(em->edges.first) free_edgelist(&em->edges);
- if(em->faces.first) free_facelist(&em->faces);
- }
- else if(event==5) {
- undo_push_mesh("Erase Only Faces");
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(faceselectedAND(efa, 1)) {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- efa= nextvl;
- }
- }
-
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-
-
-void add_primitiveMesh(int type)
-{
- EditMesh *em = G.editMesh;
- Mesh *me;
- EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
- float *curs, d, dia, phi, phid, cent[3], vec[3], imat[3][3], mat[3][3];
- float q[4], cmat[3][3];
- static short tot=32, seg=32, subdiv=2;
- short a, b, ext=0, fill=0, totoud, newob=0;
-
- if(G.scene->id.lib) return;
-
- /* this function also comes from an info window */
- if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
- if(G.vd==0) return;
-
- /* if editmode exists for other type, it exits */
- check_editmode(OB_MESH);
-
- if(G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT)) {
- G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT);
- setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
- }
-
- /* if no obedit: new object and enter editmode */
- if(G.obedit==NULL) {
- /* add_object actually returns an object ! :-)
- But it also stores the added object struct in
- G.scene->basact->object (BASACT->object) */
-
- add_object_draw(OB_MESH);
-
- G.obedit= BASACT->object;
-
- where_is_object(G.obedit);
-
- make_editMesh();
- setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
- newob= 1;
- }
- me= G.obedit->data;
-
- /* deselectall */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) eve->f&= ~1;
- eve= eve->next;
- }
-
- totoud= tot; /* store, and restore when cube/plane */
-
- /* imat and centre and size */
- Mat3CpyMat4(mat, G.obedit->obmat);
-
- curs= give_cursor();
- VECCOPY(cent, curs);
- cent[0]-= G.obedit->obmat[3][0];
- cent[1]-= G.obedit->obmat[3][1];
- cent[2]-= G.obedit->obmat[3][2];
-
- if(type!= 11) {
- Mat3CpyMat4(imat, G.vd->viewmat);
- Mat3MulVecfl(imat, cent);
- Mat3MulMat3(cmat, imat, mat);
- Mat3Inv(imat,cmat);
- } else {
- Mat3Inv(imat, mat);
- }
-
- /* ext==extrudeflag, tot==amount of vertices in basis */
-
- switch(type) {
- case 0: /* plane */
- tot= 4;
- ext= 0;
- fill= 1;
- if(newob) rename_id((ID *)G.obedit, "Plane");
- if(newob) rename_id((ID *)me, "Plane");
- break;
- case 1: /* cube */
- tot= 4;
- ext= 1;
- fill= 1;
- if(newob) rename_id((ID *)G.obedit, "Cube");
- if(newob) rename_id((ID *)me, "Cube");
- break;
- case 4: /* circle */
- if(button(&tot,3,100,"Vertices:")==0) return;
- ext= 0;
- fill= 0;
- if(newob) rename_id((ID *)G.obedit, "Circle");
- if(newob) rename_id((ID *)me, "Circle");
- break;
- case 5: /* cylinder */
- if(button(&tot,3,100,"Vertices:")==0) return;
- ext= 1;
- fill= 1;
- if(newob) rename_id((ID *)G.obedit, "Cylinder");
- if(newob) rename_id((ID *)me, "Cylinder");
- break;
- case 6: /* tube */
- if(button(&tot,3,100,"Vertices:")==0) return;
- ext= 1;
- fill= 0;
- if(newob) rename_id((ID *)G.obedit, "Tube");
- if(newob) rename_id((ID *)me, "Tube");
- break;
- case 7: /* cone */
- if(button(&tot,3,100,"Vertices:")==0) return;
- ext= 0;
- fill= 1;
- if(newob) rename_id((ID *)G.obedit, "Cone");
- if(newob) rename_id((ID *)me, "Cone");
- break;
- case 10: /* grid */
- if(button(&tot,2,100,"X res:")==0) return;
- if(button(&seg,2,100,"Y res:")==0) return;
- if(newob) rename_id((ID *)G.obedit, "Grid");
- if(newob) rename_id((ID *)me, "Grid");
- break;
- case 11: /* UVsphere */
- if(button(&seg,3,100,"Segments:")==0) return;
- if(button(&tot,3,100,"Rings:")==0) return;
- if(newob) rename_id((ID *)G.obedit, "Sphere");
- if(newob) rename_id((ID *)me, "Sphere");
- break;
- case 12: /* Icosphere */
- if(button(&subdiv,1,5,"Subdivision:")==0) return;
- if(newob) rename_id((ID *)G.obedit, "Sphere");
- if(newob) rename_id((ID *)me, "Sphere");
- break;
- case 13: /* Monkey */
- if(newob) rename_id((ID *)G.obedit, "Suzanne");
- if(newob) rename_id((ID *)me, "Suzanne");
- break;
- }
-
- dia= sqrt(2.0)*G.vd->grid;
- d= -G.vd->grid;
- phid= 2*M_PI/tot;
- phi= .25*M_PI;
-
-
- if(type<10) { /* all types except grid, sphere... */
- if(ext==0 && type!=7) d= 0;
-
- /* vertices */
- vtop= vdown= v1= v2= 0;
- for(b=0; b<=ext; b++) {
- for(a=0; a<tot; a++) {
-
- vec[0]= cent[0]+dia*sin(phi);
- vec[1]= cent[1]+dia*cos(phi);
- vec[2]= cent[2]+d;
-
- Mat3MulVecfl(imat, vec);
- eve= addvertlist(vec);
- eve->f= 1;
- if(a==0) {
- if(b==0) v1= eve;
- else v2= eve;
- }
- phi+=phid;
- }
- d= -d;
- }
- /* centre vertices */
- if(fill && type>1) {
- VECCOPY(vec,cent);
- vec[2]-= -d;
- Mat3MulVecfl(imat,vec);
- vdown= addvertlist(vec);
- if(ext || type==7) {
- VECCOPY(vec,cent);
- vec[2]-= d;
- Mat3MulVecfl(imat,vec);
- vtop= addvertlist(vec);
- }
- } else {
- vdown= v1;
- vtop= v2;
- }
- if(vtop) vtop->f= 1;
- if(vdown) vdown->f= 1;
-
- /* top and bottom face */
- if(fill) {
- if(tot==4 && (type==0 || type==1)) {
- v3= v1->next->next;
- if(ext) v4= v2->next->next;
-
- addfacelist(v3, v1->next, v1, v3->next, NULL);
- if(ext) addfacelist(v2, v2->next, v4, v4->next, NULL);
-
- }
- else {
- v3= v1;
- v4= v2;
- for(a=1; a<tot; a++) {
- addfacelist(vdown, v3, v3->next, 0, NULL);
- v3= v3->next;
- if(ext) {
- addfacelist(vtop, v4, v4->next, 0, NULL);
- v4= v4->next;
- }
- }
- if(type>1) {
- addfacelist(vdown, v3, v1, 0, NULL);
- if(ext) addfacelist(vtop, v4, v2, 0, NULL);
- }
- }
- }
- else if(type==4) { /* we need edges for a circle */
- v3= v1;
- for(a=1;a<tot;a++) {
- addedgelist(v3, v3->next, NULL);
- v3= v3->next;
- }
- addedgelist(v3, v1, NULL);
- }
- /* side faces */
- if(ext) {
- v3= v1;
- v4= v2;
- for(a=1; a<tot; a++) {
- addfacelist(v3, v3->next, v4->next, v4, NULL);
- v3= v3->next;
- v4= v4->next;
- }
- addfacelist(v3, v1, v2, v4, NULL);
- }
- else if(type==7) { /* cone */
- v3= v1;
- for(a=1; a<tot; a++) {
- addfacelist(vtop, v3->next, v3, 0, NULL);
- v3= v3->next;
- }
- addfacelist(vtop, v1, v3, 0, NULL);
- }
-
- if(type<2) tot= totoud;
-
- }
- else if(type==10) { /* grid */
- /* clear flags */
- eve= em->verts.first;
- while(eve) {
- eve->f= 0;
- eve= eve->next;
- }
- dia= G.vd->grid;
- /* one segment first: de X as */
- phi= -1.0;
- phid= 2.0/((float)tot-1);
- for(a=0;a<tot;a++) {
- vec[0]= cent[0]+dia*phi;
- vec[1]= cent[1]- dia;
- vec[2]= cent[2];
- Mat3MulVecfl(imat,vec);
- eve= addvertlist(vec);
- eve->f= 1+2+4;
- if (a) addedgelist(eve->prev, eve, NULL);
- phi+=phid;
- }
- /* extrude and translate */
- vec[0]= vec[2]= 0.0;
- vec[1]= dia*phid;
- Mat3MulVecfl(imat, vec);
- for(a=0;a<seg-1;a++) {
- extrudeflag(2,0);
- translateflag(2, vec);
- }
- }
- else if(type==11) { /* UVsphere */
- float tmat[3][3];
-
- /* 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]= cent[0]+dia*sin(phi);
- vec[1]= cent[1];
- vec[2]= cent[2]+dia*cos(phi);
- Mat3MulVecfl(imat,vec);
- eve= addvertlist(vec);
- eve->f= 1+2+4;
- if(a==0) v1= eve;
- else addedgelist(eve->prev, eve, NULL);
- phi+= phid;
- }
-
- /* extrude and rotate */
- phi= M_PI/seg;
- q[0]= cos(phi);
- q[3]= sin(phi);
- q[1]=q[2]= 0;
- QuatToMat3(q, cmat);
- Mat3MulMat3(tmat, cmat, mat);
- Mat3MulMat3(cmat, imat, tmat);
-
- for(a=0; a<seg; a++) {
- extrudeflag(2, 0);
- rotateflag(2, v1->co, cmat);
- }
- removedoublesflag(4, 0.0001);
- }
- else if(type==12) { /* Icosphere */
- EditVert *eva[12];
-
- /* 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(vec);
- eva[a]->f= 1+2;
- }
- for(a=0;a<20;a++) {
- v1= eva[ icoface[a][0] ];
- v2= eva[ icoface[a][1] ];
- v3= eva[ icoface[a][2] ];
- addfacelist(v1, v2, v3, 0, NULL);
- }
-
- dia*=200;
- for(a=1; a<subdiv; a++) subdivideflag(2, dia, 0);
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 2) {
- VecAddf(eve->co,eve->co,cent);
- Mat3MulVecfl(imat,eve->co);
- }
- eve= eve->next;
- }
- } else if (type==13) { /* 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(v);
- tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(v);
- }
- for (i=0; i<monkeynf; i++) {
- addfacelist(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);
- addfacelist(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);
- }
-
- MEM_freeN(tv);
- }
-
- if(type!=0 && type!=10) righthandfaces(1);
- countall();
-
- allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
- allqueue(REDRAWALL, 0);
- makeDispList(G.obedit);
-
- if (type==13) notice("Oooh Oooh Oooh");
-}
-
-void vertexsmooth(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- EditEdge *eed;
- float *adror, *adr, fac;
- float fvec[3];
- int teller=0;
-
- if(G.obedit==0) return;
-
- /* count */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) teller++;
- eve= eve->next;
- }
- if(teller==0) return;
-
- undo_push_mesh("Smooth");
-
- adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- eve->vn= (EditVert *)adr;
- eve->f1= 0;
- adr+= 3;
- }
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & 1) || (eed->v2->f & 1) ) {
- fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0;
- fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0;
- fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0;
-
- if((eed->v1->f & 1) && eed->v1->f1<255) {
- eed->v1->f1++;
- VecAddf((float *)eed->v1->vn, (float *)eed->v1->vn, fvec);
- }
- if((eed->v2->f & 1) && eed->v2->f1<255) {
- eed->v2->f1++;
- VecAddf((float *)eed->v2->vn, (float *)eed->v2->vn, fvec);
- }
- }
- eed= eed->next;
- }
-
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- if(eve->f1) {
- adr= (float *)eve->vn;
- fac= 0.5/(float)eve->f1;
-
- eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
- eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
- eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
- }
- eve->vn= 0;
- }
- eve= eve->next;
- }
- MEM_freeN(adror);
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-void vertexnoise(void)
-{
- EditMesh *em = G.editMesh;
- extern float Tin;
- Material *ma;
- Tex *tex;
- EditVert *eve;
- float b2, ofs, vec[3];
-
- if(G.obedit==0) return;
-
- undo_push_mesh("Noise");
-
- ma= give_current_material(G.obedit, G.obedit->actcol);
- if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
- return;
- }
- tex= ma->mtex[0]->tex;
-
- ofs= tex->turbul/200.0;
-
- eve= (struct EditVert *)em->verts.first;
- while(eve) {
- if(eve->f & 1) {
-
- if(tex->type==TEX_STUCCI) {
-
- b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
- if(tex->stype) ofs*=(b2*b2);
- vec[0]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
- vec[1]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
- vec[2]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
-
- VecAddf(eve->co, eve->co, vec);
- }
- else {
-
- externtex(ma->mtex[0], eve->co);
-
- eve->co[2]+= 0.05*Tin;
- }
- }
- eve= eve->next;
- }
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-void hide_mesh(int swap)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- EditEdge *eed;
-
- if(G.obedit==0) return;
-
- if(swap) {
- eve= em->verts.first;
- while(eve) {
- if((eve->f & 1)==0) {
- eve->xs= 3200;
- eve->h= 1;
- }
- eve= eve->next;
- }
- }
- else {
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- eve->f-=1;
- eve->xs= 3200;
- eve->h= 1;
- }
- eve= eve->next;
- }
- }
- eed= em->edges.first;
- while(eed) {
- if(eed->v1->h || eed->v2->h) eed->h= 1;
- else eed->h= 0;
- eed= eed->next;
- }
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-
-void reveal_mesh(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- EditEdge *eed;
-
- if(G.obedit==0) return;
-
- eve= em->verts.first;
- while(eve) {
- if(eve->h) {
- eve->h= 0;
- eve->f|=1;
- }
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- eed->h= 0;
- eed= eed->next;
- }
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-static float convex(float *v1, float *v2, float *v3, float *v4)
-{
- float cross[3], test[3];
- float inpr;
-
- CalcNormFloat(v1, v2, v3, cross);
- CalcNormFloat(v1, v3, v4, test);
-
- inpr= cross[0]*test[0]+cross[1]*test[1]+cross[2]*test[2];
-
- return inpr;
-}
-
-/* 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, float **uv, unsigned int *col)
-{
- if VTEST(efa, 1, efa1) {
- //if(efa->v1!=efa1->v1 && efa->v1!=efa1->v2 && efa->v1!=efa1->v3) {
- *v1= efa->v1;
- *v2= efa->v2;
- uv[0] = efa->tf.uv[0];
- uv[1] = efa->tf.uv[1];
- col[0] = efa->tf.col[0];
- col[1] = efa->tf.col[1];
- }
- else if VTEST(efa, 2, efa1) {
- //else if(efa->v2!=efa1->v1 && efa->v2!=efa1->v2 && efa->v2!=efa1->v3) {
- *v1= efa->v2;
- *v2= efa->v3;
- uv[0] = efa->tf.uv[1];
- uv[1] = efa->tf.uv[2];
- col[0] = efa->tf.col[1];
- col[1] = efa->tf.col[2];
- }
- else if VTEST(efa, 3, efa1) {
- // else if(efa->v3!=efa1->v1 && efa->v3!=efa1->v2 && efa->v3!=efa1->v3) {
- *v1= efa->v3;
- *v2= efa->v1;
- uv[0] = efa->tf.uv[2];
- uv[1] = efa->tf.uv[0];
- col[0] = efa->tf.col[2];
- col[1] = efa->tf.col[0];
- }
-
- if VTEST(efa1, 1, efa) {
- // if(efa1->v1!=efa->v1 && efa1->v1!=efa->v2 && efa1->v1!=efa->v3) {
- *v3= efa1->v1;
- uv[2] = efa1->tf.uv[0];
- col[2] = efa1->tf.col[0];
-
- *v4= efa1->v2;
- uv[3] = efa1->tf.uv[1];
- col[3] = efa1->tf.col[1];
-/*
-if(efa1->v2== *v2) {
- *v4= efa1->v3;
- uv[3] = efa1->tf.uv[2];
- } else {
- *v4= efa1->v2;
- uv[3] = efa1->tf.uv[1];
- }
- */
- }
- else if VTEST(efa1, 2, efa) {
- // else if(efa1->v2!=efa->v1 && efa1->v2!=efa->v2 && efa1->v2!=efa->v3) {
- *v3= efa1->v2;
- uv[2] = efa1->tf.uv[1];
- col[2] = efa1->tf.col[1];
-
- *v4= efa1->v3;
- uv[3] = efa1->tf.uv[2];
- col[3] = efa1->tf.col[2];
-/*
-if(efa1->v3== *v2) {
- *v4= efa1->v1;
- uv[3] = efa1->tf.uv[0];
- } else {
- *v4= efa1->v3;
- uv[3] = efa1->tf.uv[2];
- }
- */
- }
- else if VTEST(efa1, 3, efa) {
- // else if(efa1->v3!=efa->v1 && efa1->v3!=efa->v2 && efa1->v3!=efa->v3) {
- *v3= efa1->v3;
- uv[2] = efa1->tf.uv[2];
- col[2] = efa1->tf.col[2];
-
- *v4= efa1->v1;
- uv[3] = efa1->tf.uv[0];
- col[3] = efa1->tf.col[0];
-/*
-if(efa1->v1== *v2) {
- *v4= efa1->v2;
- uv[3] = efa1->tf.uv[3];
- } else {
- *v4= efa1->v1;
- uv[3] = efa1->tf.uv[0];
- }
- */
- }
- else {
- pupmenu("Wanna crash?%t|Yes Please!%x1");
- return;
- }
-
-}
-
-
-
-/* Helper functions for edge/quad edit features*/
-
-static void untag_edges(EditFace *f)
-{
- f->e1->f = 0;
- f->e2->f = 0;
- if (f->e3) f->e3->f = 0;
- if (f->e4) f->e4->f = 0;
-}
-
-#if 0
-static void mark_clear_edges(EditFace *f)
-{
- f->e1->f1 = 1;
- f->e2->f1 = 1;
- if (f->e3) f->e3->f1 = 1;
- if (f->e4) f->e4->f1 = 1;
-}
-#endif
-
-static int count_edges(EditEdge *ed)
-{
- int totedge = 0;
- while(ed) {
- ed->vn= 0;
- if( (ed->v1->f & 1) && (ed->v2->f & 1) ) totedge++;
- ed= ed->next;
- }
- return totedge;
-}
-
-/** remove and free list of tagged edges */
-static void free_tagged_edgelist(EditEdge *eed)
-{
- EditEdge *nexted;
-
- while(eed) {
- nexted= eed->next;
- if(eed->f1) {
- remedge(eed);
- free_editedge(eed);
- }
- eed= nexted;
- }
-}
-/** remove and free list of tagged faces */
-
-static void free_tagged_facelist(EditFace *efa)
-{
- EditMesh *em = G.editMesh;
- EditFace *nextvl;
-
- while(efa) {
- nextvl= efa->next;
- if(efa->f1) {
- BLI_remlink(&em->faces, efa);
- free_editface(efa);
- }
- efa= nextvl;
- }
-}
-
-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->f) */
-
-static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
-{
- int i = 0;
- EditEdge *e1, *e2, *e3;
- EVPtr *evp;
-
- /* run through edges, if selected, set pointer edge-> facearray */
- while(eed) {
- eed->f= 0;
- eed->f1= 0;
- if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
- eed->vn= (EditVert *) (&efaa[i]);
- i++;
- }
- eed= eed->next;
- }
-
-
- /* find edges pointing to 2 faces by procedure:
-
- - run through faces and their edges, increase
- face counter e->f for each face
- */
-
- while(efa) {
- efa->f1= 0;
- if(efa->v4==0) { /* if triangle */
- if(faceselectedAND(efa, 1)) {
-
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- if(e1->f<3) {
- if(e1->f<2) {
- evp= (EVPtr *) e1->vn;
- evp[(int)e1->f]= efa;
- }
- e1->f+= 1;
- }
- if(e2->f<3) {
- if(e2->f<2) {
- evp= (EVPtr *) e2->vn;
- evp[(int)e2->f]= efa;
- }
- e2->f+= 1;
- }
- if(e3->f<3) {
- if(e3->f<2) {
- evp= (EVPtr *) e3->vn;
- evp[(int)e3->f]= efa;
- }
- e3->f+= 1;
- }
- }
- }
- efa= efa->next;
- }
- return i;
-}
-
-
-void join_triangles(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *v1, *v2, *v3, *v4;
- EditFace *efa, *w;
- EVPTuple *efaar;
- EVPtr *efaa;
- EditEdge *eed, *nexted;
- int totedge, ok;
- float *uv[4];
- unsigned int col[4];
-
-
- totedge = count_edges(em->edges.first);
- if(totedge==0) return;
-
- undo_push_mesh("Convert Triangles to Quads");
-
- efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "jointris");
-
- ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
- if (G.f & G_DEBUG) {
- printf("Edges selected: %d\n", ok);
- }
-
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
-
- if(eed->f==2) { /* points to 2 faces */
-
- efaa= (EVPtr *) eed->vn;
-
- /* 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, uv, col);
-
-/*
- 4-----3 4-----3
- |\ | | |
- | \ 1 | | |
- | \ | -> | |
- | 0 \ | | |
- | \| | |
- 1-----2 1-----2
-*/
- /* make new faces */
- if( convex(v1->co, v2->co, v3->co, v4->co) > 0.01) {
- if(exist_face(v1, v2, v3, v4)==0) {
- w = addfacelist(v1, v2, v3, v4, efaa[0]);
- untag_edges(w);
-
- UVCOPY(w->tf.uv[0], uv[0]);
- UVCOPY(w->tf.uv[1], uv[1]);
- UVCOPY(w->tf.uv[2], uv[2]);
- UVCOPY(w->tf.uv[3], uv[3]);
-
- memcpy(w->tf.col, col, sizeof(w->tf.col));
- }
- /* tag as to-be-removed */
- FACE_MARKCLEAR(efaa[0]);
- FACE_MARKCLEAR(efaa[1]);
- eed->f1 = 1;
- } /* endif test convex */
- }
- }
- eed= nexted;
- }
- free_tagged_edgelist(em->edges.first);
- free_tagged_facelist(em->faces.first);
-
- MEM_freeN(efaar);
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-
-}
-
-/* quick hack, basically a copy of beauty_fill */
-void edge_flip(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *v1, *v2, *v3, *v4;
- EditEdge *eed, *nexted;
- EditFace *efa, *w;
- //void **efaar, **efaa;
- EVPTuple *efaar;
- EVPtr *efaa;
-
- float *uv[4];
- unsigned int col[4];
-
- int totedge, ok;
-
- /* - 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
- */
-
- totedge = count_edges(em->edges.first);
- if(totedge==0) return;
-
- undo_push_mesh("Flip Triangle Edges");
-
- /* 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->f==2) { /* points to 2 faces */
-
- efaa= (EVPtr *) eed->vn;
-
- /* 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, uv, col);
-
-/*
- 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) > 0.01) {
- if(exist_face(v1, v2, v3, v4)==0) {
- w = addfacelist(v1, v2, v3, 0, efaa[1]);
-
- untag_edges(w);
-
- UVCOPY(w->tf.uv[0], uv[0]);
- UVCOPY(w->tf.uv[1], uv[1]);
- UVCOPY(w->tf.uv[2], uv[2]);
-
- w->tf.col[0] = col[0]; w->tf.col[1] = col[1]; w->tf.col[2] = col[2];
-
- w = addfacelist(v1, v3, v4, 0, efaa[1]);
- untag_edges(w);
-
- UVCOPY(w->tf.uv[0], uv[0]);
- UVCOPY(w->tf.uv[1], uv[2]);
- UVCOPY(w->tf.uv[2], uv[3]);
-
- w->tf.col[0] = col[0]; w->tf.col[1] = col[2]; w->tf.col[2] = col[3];
-
- /* erase old faces and edge */
- }
- /* 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_edgelist(em->edges.first);
- free_tagged_facelist(em->faces.first);
-
- MEM_freeN(efaar);
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-void edge_rotate_selected(){
- EditEdge *eed,*temp;
- EditVert *ev;
- short edgeCount = 0;
-
- undo_push_mesh("Rotate Edges");
-
- /* Clear the f1 flag */
- for(ev = G.editMesh->verts.first;ev;ev = ev->next)
- ev->f1 &= ~1;
-
- /*clear new flag for new edges*/
- for(eed = G.editMesh->edges.first;eed;eed = eed->next){
- eed->f &= ~2;
- edgeCount++;
- }
- eed = G.editMesh->edges.first;
- while(eed){
- if(edgeCount-- < 0){
- /* To prevent an infinite loop */
- break;
- }
- if(eed->f & 2){
- /* Do not rotate newly created edges */
- eed = eed->next;
- continue;
- }
- if(eed->v1->f & 1 && eed->v2->f & 1){
- temp = eed;
- eed = eed->next;
- edge_rotate(temp);
- } else
- eed = eed->next;
-
- }
- /* clear all selections */
- for(ev = G.editMesh->verts.first;ev;ev = ev->next)
- ev->f &= ~1;
-
- /*set new selections*/
- for(ev = G.editMesh->verts.first;ev;ev = ev->next){
- if(ev->f1 & 1)
- ev->f |= 1;
- }
-
- /*clear new edge flags*/
- for(eed = G.editMesh->edges.first; eed; eed = eed->next)
- eed->f &= ~2;
-
- force_draw_all();
- screen_swapbuffers();
- return;
-}
-
-void edge_rotate(EditEdge *eed){
- EditMesh *em = G.editMesh;
- EditFace *face[2], *efa, *newFace[2];
- EditVert *faces[2][4],*v1,*v2,*v3,*v4,*vtemp;
- short facecount=0, p1=0,p2=0,p3=0,p4=0,fac1=4,fac2=4,i,j;
-
- /* check to make sure that the edge is only part of 2 faces */
- 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){
- scrarea_do_windraw(curarea);
- screen_swapbuffers();
- return;
- }
- if(facecount < 2)
- face[facecount] = efa;
- facecount++;
- }
- }
-
-
- if(facecount < 2){
- return;
- }
-
-
- /* how many edges does each face have */
- if(face[0]->e4 == NULL)
- fac1=3;
- else
- fac1=4;
- if(face[1]->e4 == NULL)
- fac2=3;
- else
- fac2=4;
-
-
- /*store the face info in a handy array */
- faces[0][0] = face[0]->v1;
- faces[0][1] = face[0]->v2;
- faces[0][2] = face[0]->v3;
- if(face[0]->e4 != NULL)
- faces[0][3] = face[0]->v4;
- else
- faces[0][3] = NULL;
-
- faces[1][0] = face[1]->v1;
- faces[1][1] = face[1]->v2;
- faces[1][2] = face[1]->v3;
- if(face[1]->e4 != NULL)
- faces[1][3] = face[1]->v4;
- else
- faces[1][3] = NULL;
-
-
- /* we don't want to rotate edges between faces that share more than one edge */
-
- j=0;
- if(face[0]->e1 == face[1]->e1 ||
- face[0]->e1 == face[1]->e2 ||
- face[0]->e1 == face[1]->e3 ||
- ((face[1]->e4) && face[0]->e1 == face[1]->e4) )
- j++;
-
- if(face[0]->e2 == face[1]->e1 ||
- face[0]->e2 == face[1]->e2 ||
- face[0]->e2 == face[1]->e3 ||
- ((face[1]->e4) && face[0]->e2 == face[1]->e4) )
- j++;
-
- if(face[0]->e3 == face[1]->e1 ||
- face[0]->e3 == face[1]->e2 ||
- face[0]->e3 == face[1]->e3 ||
- ((face[1]->e4) && face[0]->e3 == face[1]->e4) )
- j++;
-
- if(face[0]->e4){
- if(face[0]->e4 == face[1]->e1 ||
- face[0]->e4 == face[1]->e2 ||
- face[0]->e4 == face[1]->e3 ||
- ((face[1]->e4) && face[0]->e4 == face[1]->e4) )
- j++;
- }
- if(j > 1){
- return;
- }
-
- /* Coplaner Faces Only Please */
- if(Inpf(face[0]->n,face[1]->n) <= 0.000001){
- return;
- }
-
- /*get the edges verts */
- v1 = eed->v1;
- v2 = eed->v2;
- v3 = eed->v1;
- v4 = eed->v2;
-
-
- /*figure out where the edges verts lie one the 2 faces */
- for(i=0;i<4;i++){
- if(v1 == faces[0][i])
- p1 = i;
- if(v2 == faces[0][i])
- p2 = i;
- if(v1 == faces[1][i])
- p3 = i;
- if(v2 == faces[1][i])
- p4 = i;
- }
-
- /*make sure the verts are in the correct order */
- if((p1+1)%fac1 == p2){
- vtemp = v2;
- v2 = v1;
- v1 = vtemp;
-
- i = p1;
- p1 = p2;
- p2 = i;
- }
- if((p3+1)%fac2 == p4){
- vtemp = v4;
- v4 = v3;
- v3 = vtemp;
-
- i = p3;
- p3 = p4;
- p4 = i;
- }
-
-
-
- /* create the 2 new faces */
- if(fac1 == 3 && fac2 == 3){
- newFace[0] = addfacelist(faces[0][(p1+1)%3],faces[0][(p1+2)%3],faces[1][(p3+1)%3],NULL,NULL);
- newFace[1] = addfacelist(faces[1][(p3+1)%3],faces[1][(p3+2)%3],faces[0][(p1+1)%3],NULL,NULL);
-
- newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%3];
- newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%3];
- newFace[0]->tf.col[2] = face[1]->tf.col[(p3+1)%3];
- newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%3];
- newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%3];
- newFace[1]->tf.col[2] = face[0]->tf.col[(p1+1)%3];
-
- UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%3]);
- UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%3]);
- UVCOPY(newFace[0]->tf.uv[2],face[1]->tf.uv[(p3+1)%3]);
- UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%3]);
- UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%3]);
- UVCOPY(newFace[1]->tf.uv[2],face[0]->tf.uv[(p1+1)%3]);
- }
- else if(fac1 == 4 && fac2 == 3){
- newFace[0] = addfacelist(faces[0][(p1+1)%4],faces[0][(p1+2)%4],faces[0][(p1+3)%4],faces[1][(p3+1)%3],NULL);
- newFace[1] = addfacelist(faces[1][(p3+1)%3],faces[1][(p3+2)%3],faces[0][(p1+1)%4],NULL,NULL);
-
- newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%4];
- newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%4];
- newFace[0]->tf.col[2] = face[0]->tf.col[(p1+3)%4];
- newFace[0]->tf.col[3] = face[1]->tf.col[(p3+1)%3];
- newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%3];
- newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%3];
- newFace[1]->tf.col[2] = face[0]->tf.col[(p1+1)%4];
-
- UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%4]);
- UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%4]);
- UVCOPY(newFace[0]->tf.uv[2],face[0]->tf.uv[(p1+3)%4]);
- UVCOPY(newFace[0]->tf.uv[3],face[1]->tf.uv[(p3+1)%3]);
- UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%3]);
- UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%3]);
- UVCOPY(newFace[1]->tf.uv[2],face[0]->tf.uv[(p1+1)%4]);
- }
-
- else if(fac1 == 3 && fac2 == 4){
- newFace[0] = addfacelist(faces[0][(p1+1)%3],faces[0][(p1+2)%3],faces[1][(p3+1)%4],NULL,NULL);
- newFace[1] = addfacelist(faces[1][(p3+1)%4],faces[1][(p3+2)%4],faces[1][(p3+3)%4],faces[0][(p1+1)%3],NULL);
-
- newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%3];
- newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%3];
- newFace[0]->tf.col[2] = face[1]->tf.col[(p3+1)%4];
- newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%4];
- newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%4];
- newFace[1]->tf.col[2] = face[1]->tf.col[(p3+3)%4];
- newFace[1]->tf.col[3] = face[0]->tf.col[(p1+1)%3];
-
- UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%3]);
- UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%3]);
- UVCOPY(newFace[0]->tf.uv[2],face[1]->tf.uv[(p3+1)%4]);
- UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%4]);
- UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%4]);
- UVCOPY(newFace[1]->tf.uv[2],face[1]->tf.uv[(p3+3)%4]);
- UVCOPY(newFace[1]->tf.uv[3],face[0]->tf.uv[(p1+1)%3]);
-
- }
-
- else if(fac1 == 4 && fac2 == 4){
- newFace[0] = addfacelist(faces[0][(p1+1)%4],faces[0][(p1+2)%4],faces[0][(p1+3)%4],faces[1][(p3+1)%4],NULL);
- newFace[1] = addfacelist(faces[1][(p3+1)%4],faces[1][(p3+2)%4],faces[1][(p3+3)%4],faces[0][(p1+1)%4],NULL);
-
- newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%4];
- newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%4];
- newFace[0]->tf.col[2] = face[0]->tf.col[(p1+3)%4];
- newFace[0]->tf.col[3] = face[1]->tf.col[(p3+1)%4];
- newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%4];
- newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%4];
- newFace[1]->tf.col[2] = face[1]->tf.col[(p3+3)%4];
- newFace[1]->tf.col[3] = face[0]->tf.col[(p1+1)%4];
-
- UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%4]);
- UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%4]);
- UVCOPY(newFace[0]->tf.uv[2],face[0]->tf.uv[(p1+3)%4]);
- UVCOPY(newFace[0]->tf.uv[3],face[1]->tf.uv[(p3+1)%4]);
- UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%4]);
- UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%4]);
- UVCOPY(newFace[1]->tf.uv[2],face[1]->tf.uv[(p3+3)%4]);
- UVCOPY(newFace[1]->tf.uv[3],face[0]->tf.uv[(p1+1)%4]);
- }
- else{
- /*This should never happen*/
- return;
- }
-
- if(fac1 == 3)
- newFace[0]->e3->f |= 2;
- else if(fac1 == 4)
- newFace[0]->e4->f |= 2;
-
-
- /* mark the f1's of the verts for re-selection */
- faces[0][(p1+1)%fac1]->f1 |= 1;
- faces[1][(p3+1)%fac2]->f1 |= 1;
-
- /* get rid of the old edge and faces*/
- remedge(eed);
- free_editedge(eed);
- BLI_remlink(&em->faces, face[0]);
- free_editface(face[0]);
- BLI_remlink(&em->faces, face[1]);
- free_editface(face[1]);
-
- return;
-}
-
-void beauty_fill(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *v1, *v2, *v3, *v4;
- EditEdge *eed, *nexted;
- EditEdge dia1, dia2;
- EditFace *efa, *w;
- // void **efaar, **efaa;
- EVPTuple *efaar;
- EVPtr *efaa;
- float *uv[4];
- unsigned int col[4];
- float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
- int totedge, ok, notbeauty=8, onedone;
-
- /* - 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
- */
-
- totedge = count_edges(em->edges.first);
- if(totedge==0) return;
-
- if(okee("Beautify fill")==0) return;
-
- undo_push_mesh("Beauty Fill");
-
- /* 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;
-
- if(eed->f==2) {
-
- efaa = (EVPtr *) eed->vn;
-
- /* none of the faces should be treated before */
- 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, uv, col);
- if( convex(v1->co, v2->co, v3->co, v4->co) > -0.5) {
-
- /* test edges */
- if( ((long)v1) > ((long)v3) ) {
- dia1.v1= v3;
- dia1.v2= v1;
- }
- else {
- dia1.v1= v1;
- dia1.v2= v3;
- }
-
- if( ((long)v2) > ((long)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= VecLenf(v1->co, v2->co);
- len2= VecLenf(v2->co, v3->co);
- len3= VecLenf(v3->co, v4->co);
- len4= VecLenf(v4->co, v1->co);
- len5= VecLenf(v1->co, v3->co);
- len6= VecLenf(v2->co, v4->co);
-
- opp1= AreaT3Dfl(v1->co, v2->co, v3->co);
- opp2= AreaT3Dfl(v1->co, v3->co, v4->co);
-
- fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
-
- opp1= AreaT3Dfl(v2->co, v3->co, v4->co);
- opp2= AreaT3Dfl(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= addfacelist(v1, v2, v3, 0, efa);
-
- UVCOPY(w->tf.uv[0], uv[0]);
- UVCOPY(w->tf.uv[1], uv[1]);
- UVCOPY(w->tf.uv[2], uv[2]);
-
- w->tf.col[0] = col[0]; w->tf.col[1] = col[1]; w->tf.col[2] = col[2];
- w= addfacelist(v1, v3, v4, 0, efa);
-
- UVCOPY(w->tf.uv[0], uv[0]);
- UVCOPY(w->tf.uv[1], uv[2]);
- UVCOPY(w->tf.uv[2], uv[3]);
-
- w->tf.col[0] = col[0]; w->tf.col[1] = col[2]; w->tf.col[2] = col[3];
-
- 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= addfacelist(v2, v3, v4, 0, efa);
-
- UVCOPY(w->tf.uv[0], uv[1]);
- UVCOPY(w->tf.uv[1], uv[3]);
- UVCOPY(w->tf.uv[2], uv[4]);
-
- w= addfacelist(v1, v2, v4, 0, efa);
-
- UVCOPY(w->tf.uv[0], uv[0]);
- UVCOPY(w->tf.uv[1], uv[1]);
- UVCOPY(w->tf.uv[2], uv[3]);
-
- onedone= 1;
- }
- }
- }
- }
-
- }
- eed= nexted;
- }
-
- free_tagged_edgelist(em->edges.first);
- free_tagged_facelist(em->faces.first);
-
- if(onedone==0) break;
- }
-
- MEM_freeN(efaar);
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-/** tests whether selected mesh objects have tfaces */
-static int testSelected_TfaceMesh(void)
-{
- Base *base;
- Mesh *me;
-
- base = FIRSTBASE;
- while (base) {
- if TESTBASE(base) {
- if(base->object->type==OB_MESH) {
- me= base->object->data;
- if (me->tface)
- return 1;
- }
- }
- base= base->next;
- }
- return 0;
-}
-
-void join_mesh(void)
-{
- Base *base, *nextb;
- Object *ob;
- Material **matar, *ma;
- Mesh *me;
- MVert *mvert, *mvertmain;
- MEdge *medge = NULL, *medgemain;
- MFace *mface = NULL, *mfacemain;
- TFace *tface = NULL, *tfacemain;
- unsigned int *mcol=NULL, *mcolmain;
- float imat[4][4], cmat[4][4];
- int a, b, totcol, totedge=0, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT];
- int hasedges=0;
-#ifdef __NLA
- int i, j, index, haskey=0;
- bDeformGroup *dg, *odg;
- MDeformVert *dvert, *dvertmain;
-#endif
-
- if(G.obedit) return;
-
- ob= OBACT;
- if(!ob || ob->type!=OB_MESH) return;
-
- /* count */
- base= FIRSTBASE;
- while(base) {
- if TESTBASE(base) {
- if(base->object->type==OB_MESH) {
- me= base->object->data;
- totvert+= me->totvert;
- totface+= me->totface;
- if(me->medge) hasedges= 1;
-
- if(base->object == ob) ok= 1;
-
- if(me->key) {
- haskey= 1;
- break;
- }
- }
- }
- base= base->next;
- }
-
- if(haskey) {
- error("Can't join meshes with vertex keys");
- return;
- }
- /* that way the active object is always selected */
- if(ok==0) return;
-
- if(totvert==0 || totvert>MESH_MAX_VERTS) return;
-
- if(okee("Join selected meshes")==0) return;
-
-
- /* if needed add edges to other meshes */
- if(hasedges) {
- for(base= FIRSTBASE; base; base= base->next) {
- if TESTBASE(base) {
- if(base->object->type==OB_MESH) {
- me= base->object->data;
- if(me->medge==NULL) make_edges(me);
- totedge += me->totedge;
- }
- }
- }
- }
-
- /* new material indices and material array */
- matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh");
- totcol= ob->totcol;
-
- /* obact materials in new main array, is nicer start! */
- for(a=1; a<=ob->totcol; a++) {
- matar[a-1]= give_current_material(ob, a);
- id_us_plus((ID *)matar[a-1]);
- /* increase id->us : will be lowered later */
- }
-
- base= FIRSTBASE;
- while(base) {
- if TESTBASE(base) {
- if(ob!=base->object && base->object->type==OB_MESH) {
- me= base->object->data;
-#ifdef __NLA
- // Join this object's vertex groups to the base one's
- for (dg=base->object->defbase.first; dg; dg=dg->next){
- /* See if this group exists in the object */
- for (odg=ob->defbase.first; odg; odg=odg->next){
- if (!strcmp(odg->name, dg->name)){
- break;
- }
- }
- if (!odg){
- odg = MEM_callocN (sizeof(bDeformGroup), "deformGroup");
- memcpy (odg, dg, sizeof(bDeformGroup));
- BLI_addtail(&ob->defbase, odg);
- }
-
- }
- if (ob->defbase.first && ob->actdef==0)
- ob->actdef=1;
-#endif
- if(me->totvert) {
- for(a=1; a<=base->object->totcol; a++) {
- ma= give_current_material(base->object, a);
- if(ma) {
- for(b=0; b<totcol; b++) {
- if(ma == matar[b]) break;
- }
- if(b==totcol) {
- matar[b]= ma;
- ma->id.us++;
- totcol++;
- }
- if(totcol>=MAXMAT-1) break;
- }
- }
- }
- }
- if(totcol>=MAXMAT-1) break;
- }
- base= base->next;
- }
-
- me= ob->data;
- mvert= mvertmain= MEM_mallocN(totvert*sizeof(MVert), "joinmesh vert");
-
- if(totedge) medge= medgemain= MEM_callocN(totedge*sizeof(MEdge), "joinmesh edge");
- else medgemain= NULL;
-
- if (totface) mface= mfacemain= MEM_mallocN(totface*sizeof(MFace), "joinmesh face");
- else mfacemain= NULL;
-
- if(me->mcol) mcol= mcolmain= MEM_callocN(totface*4*sizeof(int), "joinmesh mcol");
- else mcolmain= NULL;
-
- /* if active object doesn't have Tfaces, but one in the selection does,
- make TFaces for active, so we don't lose texture information in the
- join process */
- if(me->tface || testSelected_TfaceMesh()) tface= tfacemain= MEM_callocN(totface*4*sizeof(TFace), "joinmesh4");
- else tfacemain= NULL;
-
-#ifdef __NLA
- if(me->dvert)
- dvert= dvertmain= MEM_callocN(totvert*sizeof(MDeformVert), "joinmesh5");
- else dvert=dvertmain= NULL;
-#endif
-
- vertofs= 0;
-
- /* inverse transorm all selected meshes in this object */
- Mat4Invert(imat, ob->obmat);
-
- base= FIRSTBASE;
- while(base) {
- nextb= base->next;
- if TESTBASE(base) {
- if(base->object->type==OB_MESH) {
-
- me= base->object->data;
-
- if(me->totvert) {
-
- memcpy(mvert, me->mvert, me->totvert*sizeof(MVert));
-
-#ifdef __NLA
- copy_dverts(dvert, me->dvert, me->totvert);
-
- /* NEW VERSION */
- if (dvertmain){
- for (i=0; i<me->totvert; i++){
- for (j=0; j<dvert[i].totweight; j++){
- // Find the old vertex group
- odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr);
- if(odg) {
- // Search for a match in the new object
- for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){
- if (!strcmp(dg->name, odg->name)){
- dvert[i].dw[j].def_nr = index;
- break;
- }
- }
- }
- }
- }
- dvert+=me->totvert;
- }
-
-#endif
- if(base->object != ob) {
- /* watch this: switch matmul order really goes wrong */
- Mat4MulMat4(cmat, base->object->obmat, imat);
-
- a= me->totvert;
- while(a--) {
- Mat4MulVecfl(cmat, mvert->co);
- mvert++;
- }
- }
- else mvert+= me->totvert;
-
- if(mcolmain) {
- if(me->mcol) memcpy(mcol, me->mcol, me->totface*4*4);
- mcol+= 4*me->totface;
- }
- }
- if(me->totface) {
-
- /* make mapping for materials */
- memset(map, 0, 4*MAXMAT);
- for(a=1; a<=base->object->totcol; a++) {
- ma= give_current_material(base->object, a);
- if(ma) {
- for(b=0; b<totcol; b++) {
- if(ma == matar[b]) {
- map[a-1]= b;
- break;
- }
- }
- }
- }
-
- memcpy(mface, me->mface, me->totface*sizeof(MFace));
-
- a= me->totface;
- while(a--) {
- mface->v1+= vertofs;
- mface->v2+= vertofs;
- if(mface->v3) mface->v3+= vertofs;
- if(mface->v4) mface->v4+= vertofs;
-
- mface->mat_nr= map[(int)mface->mat_nr];
-
- mface++;
- }
-
- if(tfacemain) {
- if(me->tface) memcpy(tface, me->tface, me->totface*sizeof(TFace));
- tface+= me->totface;
- }
-
- }
-
- if(me->totedge) {
- memcpy(medge, me->medge, me->totedge*sizeof(MEdge));
-
- a= me->totedge;
- while(a--) {
- medge->v1+= vertofs;
- medge->v2+= vertofs;
- medge++;
- }
- }
-
- vertofs+= me->totvert;
-
- if(base->object!=ob) {
- free_and_unlink_base(base);
- }
- }
- }
- base= nextb;
- }
-
- me= ob->data;
-
- if(me->mvert) MEM_freeN(me->mvert);
- me->mvert= mvertmain;
-
- if(me->medge) MEM_freeN(me->medge);
- me->medge= medgemain;
-
- if(me->mface) MEM_freeN(me->mface);
- me->mface= mfacemain;
-
-#ifdef __NLA
- if(me->dvert) free_dverts(me->dvert, me->totvert);
- me->dvert = dvertmain;
-#endif
-
- if(me->mcol) MEM_freeN(me->mcol);
- me->mcol= (MCol *)mcolmain;
-
- if(me->tface) MEM_freeN(me->tface);
- me->tface= tfacemain;
-
- me->totvert= totvert;
- me->totedge= totedge;
- me->totface= totface;
-
- /* old material array */
- for(a=1; a<=ob->totcol; a++) {
- ma= ob->mat[a-1];
- if(ma) ma->id.us--;
- }
- for(a=1; a<=me->totcol; a++) {
- ma= me->mat[a-1];
- if(ma) ma->id.us--;
- }
- if(ob->mat) MEM_freeN(ob->mat);
- if(me->mat) MEM_freeN(me->mat);
- ob->mat= me->mat= 0;
-
- if(totcol) {
- me->mat= matar;
- ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
- }
- else MEM_freeN(matar);
-
- ob->totcol= me->totcol= totcol;
- ob->colbits= 0;
-
- /* other mesh users */
- test_object_materials((ID *)me);
-
- enter_editmode();
- exit_editmode(1); // freedata, but no undo
-
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSSHADING, 0);
- makeDispList(ob);
-
- BIF_undo_push("Join Mesh");
-}
-
-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);
-}
-
-static MVert *mvertbase;
-static MFace *mfacebase;
-
-static int verg_mface(const void *v1, const void *v2)
-{
- MFace *x1, *x2;
-
- MVert *ve1, *ve2;
- int i1, i2;
-
- i1 = ((int *) v1)[0];
- i2 = ((int *) v2)[0];
-
- x1 = mfacebase + i1;
- x2 = mfacebase + i2;
-
- ve1= mvertbase+x1->v1;
- ve2= mvertbase+x2->v1;
-
- if( ve1->co[2] > ve2->co[2] ) return 1;
- else if( ve1->co[2] < ve2->co[2]) return -1;
- return 0;
-}
-
-
-void sort_faces(void)
-{
- Object *ob= OBACT;
- Mesh *me;
-
- int i, *index;
-
- if(ob==0) return;
- if(G.obedit) return;
- if(ob->type!=OB_MESH) return;
-
- if(okee("Sort faces in Z axis")==0) return;
- me= ob->data;
- if(me->totface==0) return;
-
-/* create index list */
- index = (int *) MEM_mallocN(sizeof(int) * me->totface, "sort faces");
- for (i = 0; i < me->totface; i++) {
- index[i] = i;
- }
- mvertbase= me->mvert;
- mfacebase = me->mface;
-
-/* sort index list instead of faces itself
- and apply this permutation to the face list plus
- to the texture faces */
- qsort(index, me->totface, sizeof(int), verg_mface);
-
- permutate(mfacebase, me->totface, sizeof(MFace), index);
- if (me->tface)
- permutate(me->tface, me->totface, sizeof(TFace), index);
-
- MEM_freeN(index);
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-void vertices_to_sphere(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- Object *ob= OBACT;
- float *curs, len, vec[3], cent[3], fac, facm, imat[3][3], bmat[3][3];
- int tot;
- short perc=100;
-
- if(ob==0) return;
- TEST_EDITMESH
-
- if(button(&perc, 1, 100, "Percentage:")==0) return;
-
- undo_push_mesh("To Sphere");
-
- fac= perc/100.0;
- facm= 1.0-fac;
-
- Mat3CpyMat4(bmat, ob->obmat);
- Mat3Inv(imat, bmat);
-
- /* centre */
- curs= give_cursor();
- cent[0]= curs[0]-ob->obmat[3][0];
- cent[1]= curs[1]-ob->obmat[3][1];
- cent[2]= curs[2]-ob->obmat[3][2];
- Mat3MulVecfl(imat, cent);
-
- len= 0.0;
- tot= 0;
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- tot++;
- len+= VecLenf(cent, eve->co);
- }
- eve= eve->next;
- }
- len/=tot;
-
- if(len==0.0) len= 10.0;
-
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- vec[0]= eve->co[0]-cent[0];
- vec[1]= eve->co[1]-cent[1];
- vec[2]= eve->co[2]-cent[2];
-
- Normalise(vec);
-
- eve->co[0]= fac*(cent[0]+vec[0]*len) + facm*eve->co[0];
- eve->co[1]= fac*(cent[1]+vec[1]*len) + facm*eve->co[1];
- eve->co[2]= fac*(cent[2]+vec[2]*len) + facm*eve->co[2];
-
- }
- eve= eve->next;
- }
-
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-/* Got this from scanfill.c. You will need to juggle around the
- * callbacks for the scanfill.c code a bit for this to work. */
-void fill_mesh(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve,*v1;
- EditEdge *eed,*e1,*nexted;
- EditFace *efa,*nextvl;
- short ok;
-
- if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return;
-
- waitcursor(1);
-
- undo_push_mesh("Fill");
-
- /* copy all selected vertices */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
- v1= BLI_addfillvert(eve->co);
- eve->vn= v1;
- v1->vn= eve;
- v1->h= 0;
- }
- eve= eve->next;
- }
- /* copy all selected edges */
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
- e1= BLI_addfilledge(eed->v1->vn, eed->v2->vn);
- e1->v1->h++;
- e1->v2->h++;
- }
- eed= eed->next;
- }
- /* from all selected faces: remove vertices and edges verwijderen to prevent doubles */
- /* all edges add values, faces subtract,
- then remove edges with vertices ->h<2 */
- efa= em->faces.first;
- ok= 0;
- while(efa) {
- nextvl= efa->next;
- if( faceselectedAND(efa, 1) ) {
- efa->v1->vn->h--;
- efa->v2->vn->h--;
- efa->v3->vn->h--;
- if(efa->v4) efa->v4->vn->h--;
- ok= 1;
-
- }
- efa= nextvl;
- }
- if(ok) { /* there are faces selected */
- eed= filledgebase.first;
- while(eed) {
- nexted= eed->next;
- if(eed->v1->h<2 || eed->v2->h<2) {
- BLI_remlink(&filledgebase,eed);
- }
- eed= nexted;
- }
- }
-
- /* to make edgefill work */
- BLI_setScanFillObjectRef(G.obedit);
- BLI_setScanFillColourRef(&G.obedit->actcol);
-
- ok= BLI_edgefill(0);
-
- /* printf("time: %d\n",(clock()-tijd)/1000); */
-
- if(ok) {
- efa= fillfacebase.first;
- while(efa) {
- addfacelist(efa->v1->vn, efa->v2->vn, efa->v3->vn, 0, efa);
- efa= efa->next;
- }
- }
- /* else printf("fill error\n"); */
-
- BLI_end_edgefill();
-
- waitcursor(0);
-
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-}
-
-/* ***************** */
-
-/* this one for NOT in editmode
-
-(only used by external modules, that is, until now by the
-python NMesh module)
-
-TODO: Probably it's better to convert the mesh into a EditMesh, call
-vertexnormals() and convert it back to a Mesh again.
-
-*/
-
-void vertexnormals_mesh(Mesh *me, float *extverts)
-{
- MVert *mvert;
- MFace *mface;
- float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp;
- float *f1, *f2, *f3, *f4, xn, yn, zn, *normals;
- float *v1, *v2, *v3, *v4, len, vnor[3];
- int a, testflip;
-
- if(me->totvert==0) return;
-
- testflip= (me->flag & ME_NOPUNOFLIP)==0;
- if((me->flag & ME_TWOSIDED)==0) testflip= 0; /* large angles */
-
- if(me->totface==0) {
- /* fake vertex normals for 'halopuno' (render option) */
- mvert= me->mvert;
- for(a=0; a<me->totvert; a++, mvert++) {
- VECCOPY(n1, mvert->co);
- Normalise(n1);
- mvert->no[0]= 32767.0*n1[0];
- mvert->no[1]= 32767.0*n1[1];
- mvert->no[2]= 32767.0*n1[2];
- }
- return;
- }
-
- normals= MEM_callocN(me->totvert*3*sizeof(float), "normals");
-
- /* calculate cosine angles, and add to vertex normal */
- mface= me->mface;
- mvert= me->mvert;
- for(a=0; a<me->totface; a++, mface++) {
-
- if(mface->v3==0) continue;
-
- if(extverts) {
- v1= extverts+3*mface->v1;
- v2= extverts+3*mface->v2;
- v3= extverts+3*mface->v3;
- v4= extverts+3*mface->v4;
- }
- else {
- v1= (mvert+mface->v1)->co;
- v2= (mvert+mface->v2)->co;
- v3= (mvert+mface->v3)->co;
- v4= (mvert+mface->v4)->co;
- }
-
- VecSubf(n1, v2, v1);
- VecSubf(n2, v3, v2);
- Normalise(n1);
- Normalise(n2);
-
- if(mface->v4==0) {
- VecSubf(n3, v1, v3);
- Normalise(n3);
-
- co[0]= saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]);
- co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
- co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
-
- }
- else {
- VecSubf(n3, v4, v3);
- VecSubf(n4, v1, v4);
- Normalise(n3);
- Normalise(n4);
-
- co[0]= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
- co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
- co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
- co[3]= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
- }
-
- CalcNormFloat(v1, v2, v3, vnor);
-
- temp= normals+3*mface->v1;
- if(testflip && contrpuntnorm(vnor, temp) ) co[0]= -co[0];
- temp[0]+= co[0]*vnor[0];
- temp[1]+= co[0]*vnor[1];
- temp[2]+= co[0]*vnor[2];
-
- temp= normals+3*mface->v2;
- if(testflip && contrpuntnorm(vnor, temp) ) co[1]= -co[1];
- temp[0]+= co[1]*vnor[0];
- temp[1]+= co[1]*vnor[1];
- temp[2]+= co[1]*vnor[2];
-
- temp= normals+3*mface->v3;
- if(testflip && contrpuntnorm(vnor, temp) ) co[2]= -co[2];
- temp[0]+= co[2]*vnor[0];
- temp[1]+= co[2]*vnor[1];
- temp[2]+= co[2]*vnor[2];
-
- if(mface->v4) {
- temp= normals+3*mface->v4;
- if(testflip && contrpuntnorm(vnor, temp) ) co[3]= -co[3];
- temp[0]+= co[3]*vnor[0];
- temp[1]+= co[3]*vnor[1];
- temp[2]+= co[3]*vnor[2];
- }
- }
-
- /* normalize vertex normals */
- mvert= me->mvert;
- for(a=0; a<me->totvert; a++, mvert++) {
- len= Normalise(normals+3*a);
- if(len!=0.0) {
- VECCOPY(n1, normals+3*a);
- Normalise(n1);
-
- mvert->no[0]= 32767.0*n1[0];
- mvert->no[1]= 32767.0*n1[1];
- mvert->no[2]= 32767.0*n1[2];
- }
- }
-
- /* vertex normal flipping flags, for during render */
- mface= me->mface;
- mvert= me->mvert;
- for(a=0; a<me->totface; a++, mface++) {
- mface->puno=0;
-
- if(mface->v3==0) continue;
-
- if(extverts) {
- v1= extverts+3*mface->v1;
- v2= extverts+3*mface->v2;
- v3= extverts+3*mface->v3;
- }
- else {
- v1= (mvert+mface->v1)->co;
- v2= (mvert+mface->v2)->co;
- v3= (mvert+mface->v3)->co;
- }
-
- CalcNormFloat(v1, v2, v3, vnor);
-
- if(testflip) {
- f1= normals + 3*mface->v1;
- f2= normals + 3*mface->v2;
- f3= normals + 3*mface->v3;
-
- fac1= vnor[0]*f1[0] + vnor[1]*f1[1] + vnor[2]*f1[2];
- if(fac1<0.0) {
- mface->puno = ME_FLIPV1;
- }
- fac2= vnor[0]*f2[0] + vnor[1]*f2[1] + vnor[2]*f2[2];
- if(fac2<0.0) {
- mface->puno += ME_FLIPV2;
- }
- fac3= vnor[0]*f3[0] + vnor[1]*f3[1] + vnor[2]*f3[2];
- if(fac3<0.0) {
- mface->puno += ME_FLIPV3;
- }
- if(mface->v4) {
- f4= normals + 3*mface->v4;
- fac4= vnor[0]*f4[0] + vnor[1]*f4[1] + vnor[2]*f4[2];
- if(fac4<0.0) {
- mface->puno += ME_FLIPV4;
- }
- }
- }
- /* proj for cubemap! */
- xn= fabs(vnor[0]);
- yn= fabs(vnor[1]);
- zn= fabs(vnor[2]);
-
- if(zn>xn && zn>yn) mface->puno += ME_PROJXY;
- else if(yn>xn && yn>zn) mface->puno += ME_PROJXZ;
- else mface->puno += ME_PROJYZ;
-
- }
-
- MEM_freeN(normals);
-}
-
-/***/
-
-static int editmesh_nfaces_selected(void)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa;
- int count= 0;
-
- for (efa= em->faces.first; efa; efa= efa->next)
- if (faceselectedAND(efa, SELECT))
- count++;
-
- return count;
-}
-
-static int editmesh_nvertices_selected(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- int count= 0;
-
- for (eve= em->verts.first; eve; eve= eve->next)
- if (eve->f & SELECT)
- count++;
-
- return count;
-}
-
-static void editmesh_calc_selvert_center(float cent_r[3])
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- int nsel= 0;
-
- cent_r[0]= cent_r[1]= cent_r[0]= 0.0;
-
- for (eve= em->verts.first; eve; eve= eve->next) {
- if (eve->f & SELECT) {
- cent_r[0]+= eve->co[0];
- cent_r[1]+= eve->co[1];
- cent_r[2]+= eve->co[2];
- nsel++;
- }
- }
-
- if (nsel) {
- cent_r[0]/= nsel;
- cent_r[1]/= nsel;
- cent_r[2]/= nsel;
- }
-}
-
-static int tface_is_selected(TFace *tf)
-{
- return (!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT));
-}
-
-static int faceselect_nfaces_selected(Mesh *me)
-{
- int i, count= 0;
-
- for (i=0; i<me->totface; i++) {
- MFace *mf= ((MFace*) me->mface) + i;
- TFace *tf= ((TFace*) me->tface) + i;
-
- if (mf->v3 && tface_is_selected(tf))
- count++;
- }
-
- return count;
-}
-
- /* XXX, code for both these functions should be abstract,
- * then unified, then written for other things (like objects,
- * which would use same as vertices method), then added
- * to interface! Hoera! - zr
- */
-void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
-{
- if (!faceselect_nfaces_selected(me)) {
- error("No faces selected.");
- } else {
- float norm[3];
- int i;
-
- norm[0]= norm[1]= norm[2]= 0.0;
- for (i=0; i<me->totface; i++) {
- MFace *mf= ((MFace*) me->mface) + i;
- TFace *tf= ((TFace*) me->tface) + i;
-
- if (mf->v3 && tface_is_selected(tf)) {
- float *v1, *v2, *v3, fno[3];
-
- v1= me->mvert[mf->v1].co;
- v2= me->mvert[mf->v2].co;
- v3= me->mvert[mf->v3].co;
- if (mf->v4) {
- float *v4= me->mvert[mf->v4].co;
- CalcNormFloat4(v1, v2, v3, v4, fno);
- } else {
- CalcNormFloat(v1, v2, v3, fno);
- }
-
- norm[0]+= fno[0];
- norm[1]+= fno[1];
- norm[2]+= fno[2];
- }
- }
-
- view3d_align_axis_to_vector(v3d, axis, norm);
- }
-}
-
-void editmesh_align_view_to_selected(View3D *v3d, int axis)
-{
- EditMesh *em = G.editMesh;
- int nselverts= editmesh_nvertices_selected();
-
- if (nselverts<3) {
- if (nselverts==0) {
- error("No faces or vertices selected.");
- } else {
- error("At least one face or three vertices must be selected.");
- }
- } else if (editmesh_nfaces_selected()) {
- float norm[3];
- EditFace *efa;
-
- norm[0]= norm[1]= norm[2]= 0.0;
- for (efa= em->faces.first; efa; efa= efa->next) {
- if (faceselectedAND(efa, SELECT)) {
- float fno[3];
- if (efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, fno);
- else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, fno);
- /* XXX, fixme, should be flipped intp a
- * consistent direction. -zr
- */
- norm[0]+= fno[0];
- norm[1]+= fno[1];
- norm[2]+= fno[2];
- }
- }
-
- Mat4Mul3Vecfl(G.obedit->obmat, norm);
- view3d_align_axis_to_vector(v3d, axis, norm);
- } else {
- float cent[3], norm[3];
- EditVert *eve, *leve= NULL;
-
- norm[0]= norm[1]= norm[2]= 0.0;
- editmesh_calc_selvert_center(cent);
- for (eve= em->verts.first; eve; eve= eve->next) {
- if (eve->f & SELECT) {
- if (leve) {
- float tno[3];
- CalcNormFloat(cent, leve->co, eve->co, tno);
-
- /* XXX, fixme, should be flipped intp a
- * consistent direction. -zr
- */
- norm[0]+= tno[0];
- norm[1]+= tno[1];
- norm[2]+= tno[2];
- }
- leve= eve;
- }
- }
-
- Mat4Mul3Vecfl(G.obedit->obmat, norm);
- view3d_align_axis_to_vector(v3d, axis, norm);
- }
-}
-
-/*
-
-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,
-
-this doesn't belong here.....
- */
-
-CutCurve *get_mouse_trail(int *len, char mode){
-
- CutCurve *curve,*temp;
- short event, val, ldown=0, restart=0, rubberband=0;
- short mval[2], lockaxis=0, lockx=0, locky=0, lastx=0, lasty=0;
- int i=0, j, blocks=1, lasti=0;
-
- *len=0;
- curve=(CutCurve *)MEM_callocN(1024*sizeof(CutCurve), "MouseTrail");
-
- if (!curve) {
- printf("failed to allocate memory in get_mouse_trail()\n");
- return(NULL);
- }
- mywinset(curarea->win);
- glDrawBuffer(GL_FRONT);
-
- headerprint("LMB to draw, Enter to finish, ESC to abort.");
-
- persp(PERSP_WIN);
-
- glColor3ub(200, 200, 0);
-
- while(TRUE) {
-
- event=extern_qread(&val); /* Enter or RMB indicates finish */
- if(val) {
- if(event==RETKEY || event==PADENTER) break;
- }
-
- if( event==ESCKEY || event==RIGHTMOUSE ) {
- if (curve) MEM_freeN(curve);
- *len=0;
- glFlush();
- glDrawBuffer(GL_BACK);
- return(NULL);
- break;
- }
-
- if (rubberband) { /* rubberband mode, undraw last rubberband */
- glLineWidth(2.0);
- sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
- glLineWidth(1.0);
- glFlush();
- rubberband=0;
- }
-
- getmouseco_areawin(mval);
-
- if (lockaxis==1) mval[1]=locky;
- if (lockaxis==2) mval[0]=lockx;
-
- if ( ((i==0) || (mval[0]!=curve[i-1].x) || (mval[1]!=curve[i-1].y))
- && (get_mbut() & L_MOUSE) ){ /* record changes only, if LMB down */
-
- lastx=curve[i].x=mval[0];
- lasty=curve[i].y=mval[1];
-
- lockaxis=0;
-
- i++;
-
- ldown=1;
- if (restart) {
- for(j=1;j<i;j++) sdrawXORline(curve[j-1].x, curve[j-1].y, curve[j].x, curve[j].y);
- if (rubberband) sdrawXORline(curve[j].x, curve[j].y, mval[0], mval[1]);
- glFlush();
- rubberband=0;
- lasti=i=0;
- restart=0;
- ldown=0;
- }
- }
-
- if ((event==MIDDLEMOUSE)&&(get_mbut()&M_MOUSE)&&(i)){/*MMB Down*/
- /*determine which axis to lock to, or clear if locked */
- if (lockaxis) lockaxis=0;
- else if (abs(curve[i-1].x-mval[0]) > abs(curve[i-1].y-mval[1])) lockaxis=1;
- else lockaxis=2;
-
- if (lockaxis) {
- lockx=lastx;
- locky=lasty;
- }
- }
-
- if ((i>1)&&(i!=lasti)) { /*Draw recorded part of curve */
- sdrawline(curve[i-2].x, curve[i-2].y, curve[i-1].x, curve[i-1].y);
- glFlush();
- }
-
- if ((i==lasti)&&(i>0)) { /*Draw rubberband */
- glLineWidth(2.0);
- sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
- glLineWidth(1.0);
- glFlush();
- rubberband=1;
- }
- lasti=i;
-
- if (i>=blocks*1024) { /* reallocate data if out of room */
- temp=curve;
- curve=(CutCurve *)MEM_callocN((blocks+1)*1024*sizeof(CutCurve), "MouseTrail");
- if (!curve) {
- printf("failed to re-allocate memory in get_mouse_trail()\n");
- return(NULL);
- }
- memcpy(curve, temp, blocks*1024*sizeof(CutCurve));
- blocks++;
- MEM_freeN(temp);
- }
- }
-
- glFlush();
- glDrawBuffer(GL_BACK);
- persp(PERSP_VIEW);
-
- *len=i;
-
- return(curve);
-}
-
-/* ******************************************************************** */
-/* 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).
-*/
-
-void KnifeSubdivide(char mode){
- EditMesh *em = G.editMesh;
- int oldcursor, len=0;
- short isect=0;
- CutCurve *curve;
- EditEdge *eed;
- Window *win;
-
- if (G.obedit==0) return;
-
- if (editmesh_nvertices_selected() < 2) {
- error("No edges are selected to operate on");
- return;
- }
-
- if (mode==KNIFE_PROMPT) {
- short val= pupmenu("Cut Type %t|Exact Line%x1|Midpoints%x2");
- if(val<1) return;
- mode= val; // warning, mode is char, pupmenu returns -1 with ESC
- }
-
- undo_push_mesh("Knife");
-
- calc_meshverts_ext(); /*Update screen coords for current window */
-
- /* Set a knife cursor here */
- oldcursor=get_cursor();
-
- win=winlay_get_active_window();
-
- SetBlenderCursor(BC_KNIFECURSOR);
-
- curve=get_mouse_trail(&len, TRAIL_MIXED);
-
- if (curve && len && mode){
- eed= em->edges.first;
- while(eed) {
- if((eed->v1->f&1)&&(eed->v2->f&1)){
- isect=seg_intersect(eed, curve, len);
- if (isect) eed->f=1;
- else eed->f=0;
- eed->f1=isect;
- //printf("isect=%i\n", isect);
- }
- else {
- eed->f=0;
- eed->f1=0;
- }
- eed= eed->next;
- }
-
- if (mode==1) subdivideflag(1, 0, B_KNIFE|B_PERCENTSUBD);
- else if (mode==2) subdivideflag(1, 0, B_KNIFE);
-
- eed=em->edges.first;
- while(eed){
- eed->f=0;
- eed->f1=0;
- eed=eed->next;
- }
- }
- /* Return to old cursor and flags...*/
-
- addqueue(curarea->win, REDRAW, 0);
- window_set_cursor(win, oldcursor);
- if (curve) MEM_freeN(curve);
-}
-
-/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
-
-short seg_intersect(EditEdge *e, CutCurve *c, int len){
-#define MAXSLOPE 100000
- short isect=0;
- 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[2], co[4];
- int i;
-
- /* Get screen coords of verts (v->xs and v->ys clip if off screen */
- VECCOPY(co, e->v1->co);
- co[3]= 1.0;
- Mat4MulVec4fl(G.obedit->obmat, co);
- project_float(co, scr);
- x21=scr[0];
- y21=scr[1];
-
- VECCOPY(co, e->v2->co);
- co[3]= 1.0;
- Mat4MulVec4fl(G.obedit->obmat, co);
- project_float(co, scr);
- 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;
- }
- 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)){
- 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(isect);
-}
-
-
-void LoopMenu(){ /* Called by KKey */
-
- short ret;
-
- ret=pupmenu("Loop/Cut Menu %t|Face Loop Select %x1|Face Loop Cut %x2|"
- "Knife (Exact) %x3|Knife (Midpoints)%x4|");
-
- switch (ret){
- case 1:
- loopoperations(LOOP_SELECT);
- break;
- case 2:
- loopoperations(LOOP_CUT);
- break;
- case 3:
- KnifeSubdivide(KNIFE_EXACT);
- break;
- case 4:
- KnifeSubdivide(KNIFE_MIDPOINT);
- }
-
-}
-
-/*********************** EDITMESH UNDO ********************************/
-/* Mesh Edit undo by Alexander Ewring, */
-/* ported by Robert Wenzlaff */
-/* */
-/* Any meshedit function wishing to create an undo step, calls */
-/* undo_push_mesh("menu_name_of_step"); */
-
-Mesh *undo_new_mesh(void)
-{
- return(MEM_callocN(sizeof(Mesh), "undo_mesh"));
-}
-
-void undo_free_mesh(Mesh *me)
-{
- if(me->mat) MEM_freeN(me->mat);
- if(me->orco) MEM_freeN(me->orco);
- if(me->mvert) MEM_freeN(me->mvert);
- if(me->medge) MEM_freeN(me->medge);
- if(me->mface) MEM_freeN(me->mface);
- if(me->tface) MEM_freeN(me->tface);
- if(me->dvert) free_dverts(me->dvert, me->totvert);
- if(me->mcol) MEM_freeN(me->mcol);
- if(me->msticky) MEM_freeN(me->msticky);
- if(me->bb) MEM_freeN(me->bb);
- if(me->disp.first) freedisplist(&me->disp);
- MEM_freeN(me);
-}
-
-
-void undo_push_mesh(char *name)
-{
- Mesh *me;
- int i;
-
- countall();
-
- G.undo_edit_level++;
-
- if (G.undo_edit_level<0) {
- printf("undo: ERROR: G.undo_edit_level negative\n");
- return;
- }
-
-
- if (G.undo_edit[G.undo_edit_level].datablock != 0) {
- undo_free_mesh(G.undo_edit[G.undo_edit_level].datablock);
- }
- if (strcmp(name, "U")!=0) {
- for (i=G.undo_edit_level+1; i<(U.undosteps-1); i++) {
- if (G.undo_edit[i].datablock != 0) {
- undo_free_mesh(G.undo_edit[i].datablock);
- G.undo_edit[i].datablock= 0;
- }
- }
- G.undo_edit_highest= G.undo_edit_level;
- }
-
- me= undo_new_mesh();
-
- if (G.undo_edit_level>=U.undosteps) {
- G.undo_edit_level--;
- undo_free_mesh((Mesh*)G.undo_edit[0].datablock);
- G.undo_edit[0].datablock= 0;
- for (i=0; i<(U.undosteps-1); i++) {
- G.undo_edit[i]= G.undo_edit[i+1];
- }
- }
-
- if (strcmp(name, "U")!=0) strcpy(G.undo_edit[G.undo_edit_level].name, name);
- //printf("undo: saving block: %d [%s]\n", G.undo_edit_level, G.undo_edit[G.undo_edit_level].name);
-
- G.undo_edit[G.undo_edit_level].datablock= (void*)me;
- load_editMesh_real(me, 1);
-}
-
-void undo_pop_mesh(int steps) /* steps == 1 is one step */
-{
- if (G.undo_edit_level > (steps-2)) {
- undo_push_mesh("U");
- G.undo_edit_level-= steps;
-
- //printf("undo: restoring block: %d [%s]\n", G.undo_edit_level, G.undo_edit[G.undo_edit_level].name); -
- make_editMesh_real((Mesh*)G.undo_edit[G.undo_edit_level].datablock);
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
- G.undo_edit_level--;
- } else error("No more steps to undo");
-}
-
-
-void undo_redo_mesh(void)
-{
- if ( (G.undo_edit[G.undo_edit_level+2].datablock) &&
- ( (G.undo_edit_level+1) <= G.undo_edit_highest ) ) {
- G.undo_edit_level++;
-
- //printf("redo: restoring block: %d [%s]\n", G.undo_edit_level+1, G.undo_edit[G.undo_edit_level+1].name);-
- make_editMesh_real((Mesh*)G.undo_edit[G.undo_edit_level+1].datablock);
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
- } else error("No more steps to redo");
-}
-
-void undo_clear_mesh(void)
-{
- int i;
- Mesh *me;
-
- for (i=0; i<=UNDO_EDIT_MAX; i++) {
- me= (Mesh*) G.undo_edit[i].datablock;
- if (me) {
- //printf("undo: freeing %d\n", i);
- undo_free_mesh(me);
- G.undo_edit[i].datablock= 0;
- }
- }
-}
-
-void undo_menu_mesh(void)
-{
- short event=66;
- int i;
- char menu[2080], temp[64];
-
- TEST_EDITMESH
-
- strcpy(menu, "Undo %t|%l");
- strcat(menu, "|All changes%x1|%l");
-
- for (i=G.undo_edit_level; i>=0; i--) {
- snprintf(temp, 64, "|%s%%x%d", G.undo_edit[i].name, i+2);
- strcat(menu, temp);
- }
-
- event=pupmenu_col(menu, 20);
-
- if(event<1) return;
-
- if (event==1) remake_editMesh();
- else undo_pop_mesh(G.undo_edit_level-event+3);
-}
-
-/******************* BEVEL CODE STARTS HERE ********************/
-
-void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3])
-{
- float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac;
-
- VecSubf(a, v1, v2);
- VecSubf(c, v3, v2);
-
- Crossf(n_a, a, no);
- Normalise(n_a);
- Crossf(n_c, no, c);
- Normalise(n_c);
-
- Normalise(a);
- Normalise(c);
- ac = Inpf(a, c);
-
- if (ac == 1 || ac == -1) {
- midvec[0] = midvec[1] = midvec[2] = 0;
- return;
- }
- ac2 = ac * ac;
- fac = sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1);
- VecAddf(mid, n_c, n_a);
- Normalise(mid);
- VecMulf(mid, d * fac);
- VecAddf(mid, mid, v2);
- VecCopyf(midvec, mid);
-}
-
-/* Finds the new point using the sinus law to extrapolate a triangle
- Lots of sqrts which would not be good for a real time algo
- Using the mid point of the extrapolation of both sides
- Useless for coplanar quads, but that doesn't happen too often */
-void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3])
-{
- float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3];
-
- VecSubf(a, v3, v2);
- l_a = Normalise(a);
- VecSubf(b, v4, v3);
- Normalise(b);
- VecSubf(c, v1, v2);
- Normalise(c);
-
- s_b = Inpf(a, c);
- s_b = sqrt(1 - (s_b * s_b));
- s_a = Inpf(b, c);
- s_a = sqrt(1 - (s_a * s_a));
- VecMulf(a, -1);
- s_c = Inpf(a, b);
- s_c = sqrt(1 - (s_c * s_c));
-
- l_b = s_b * l_a / s_a;
- l_c = s_c * l_a / s_a;
-
- VecMulf(b, l_b);
- VecMulf(c, l_c);
-
- VecAddf(Pos1, v2, c);
- VecAddf(Pos2, v3, b);
-
- VecAddf(Dir, Pos1, Pos2);
- VecMulf(Dir, 0.5);
-
- bevel_displace_vec(midvec, v3, Dir, v2, d, no);
-
-}
-
-
-char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no)
-{
- float o_a[3], a[3], o_c[3], c[3];
-
- VecSubf(o_a, o_v1, o_v2);
- VecSubf(a, v1, v2);
-
- Crossf(o_c, o_a, no);
- Crossf(c, a, no);
-
- if (Inpf(c, o_c) <= 0)
- return 1;
- else
- return 0;
-}
-
-// Detects and fix a quad wrapping after the resize
-// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal
-void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no)
-{
- float vec[3];
- char wrap[4];
-
- // Quads can wrap partially. Watch out
- wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2
- wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3
- wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4
- wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1
-
- // Edge 1 inverted
- if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) {
- fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no);
- VECCOPY(v1, vec);
- VECCOPY(v2, vec);
- }
- // Edge 2 inverted
- else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) {
- fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no);
- VECCOPY(v2, vec);
- VECCOPY(v3, vec);
- }
- // Edge 3 inverted
- else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
- fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no);
- VECCOPY(v3, vec);
- VECCOPY(v4, vec);
- }
- // Edge 4 inverted
- else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) {
- fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no);
- VECCOPY(v4, vec);
- VECCOPY(v1, vec);
- }
- // Edge 2 and 4 inverted
- else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) {
- VecAddf(vec, v2, v3);
- VecMulf(vec, 0.5);
- VECCOPY(v2, vec);
- VECCOPY(v3, vec);
- VecAddf(vec, v1, v4);
- VecMulf(vec, 0.5);
- VECCOPY(v1, vec);
- VECCOPY(v4, vec);
- }
- // Edge 1 and 3 inverted
- else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
- VecAddf(vec, v1, v2);
- VecMulf(vec, 0.5);
- VECCOPY(v1, vec);
- VECCOPY(v2, vec);
- VecAddf(vec, v3, v4);
- VecMulf(vec, 0.5);
- VECCOPY(v3, vec);
- VECCOPY(v4, vec);
- }
- // Totally inverted
- else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) {
- VecAddf(vec, v1, v2);
- VecAddf(vec, vec, v3);
- VecAddf(vec, vec, v4);
- VecMulf(vec, 0.25);
- VECCOPY(v1, vec);
- VECCOPY(v2, vec);
- VECCOPY(v3, vec);
- VECCOPY(v4, vec);
- }
-
-}
-
-// Detects and fix a tri wrapping after the resize
-// Arguments are the orginal verts followed by the final verts and the normal
-// Triangles cannot wrap partially (not in this situation
-void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no)
-{
- if (detect_wrap(o_v1, o_v2, v1, v2, no)) {
- float vec[3];
- VecAddf(vec, o_v1, o_v2);
- VecAddf(vec, vec, o_v3);
- VecMulf(vec, 1.0/3.0);
- VECCOPY(v1, vec);
- VECCOPY(v2, vec);
- VECCOPY(v3, vec);
- }
-}
-
-void bevel_shrink_faces(float d, int flag)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa;
- float vec[3], no[3], v1[3], v2[3], v3[3], v4[3];
-
- /* move edges of all faces with efa->f1 & flag closer towards their centres */
- efa= em->faces.first;
- while (efa) {
- if (efa->f1 & flag) {
- VECCOPY(v1, efa->v1->co);
- VECCOPY(v2, efa->v2->co);
- VECCOPY(v3, efa->v3->co);
- VECCOPY(no, efa->n);
- if (efa->v4 == NULL) {
- bevel_displace_vec(vec, v1, v2, v3, d, no);
- VECCOPY(efa->v2->co, vec);
- bevel_displace_vec(vec, v2, v3, v1, d, no);
- VECCOPY(efa->v3->co, vec);
- bevel_displace_vec(vec, v3, v1, v2, d, no);
- VECCOPY(efa->v1->co, vec);
-
- fix_bevel_tri_wrap(v1, v2, v3, efa->v1->co, efa->v2->co, efa->v3->co, no);
- } else {
- VECCOPY(v4, efa->v4->co);
- bevel_displace_vec(vec, v1, v2, v3, d, no);
- VECCOPY(efa->v2->co, vec);
- bevel_displace_vec(vec, v2, v3, v4, d, no);
- VECCOPY(efa->v3->co, vec);
- bevel_displace_vec(vec, v3, v4, v1, d, no);
- VECCOPY(efa->v4->co, vec);
- bevel_displace_vec(vec, v4, v1, v2, d, no);
- VECCOPY(efa->v1->co, vec);
-
- fix_bevel_quad_wrap(v1, v2, v3, v4, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, d, no);
- }
- }
- efa= efa->next;
- }
-}
-
-void bevel_shrink_draw(float d, int flag)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa;
- float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3];
-
- /* move edges of all faces with efa->f1 & flag closer towards their centres */
- efa= em->faces.first;
- while (efa) {
- VECCOPY(v1, efa->v1->co);
- VECCOPY(v2, efa->v2->co);
- VECCOPY(v3, efa->v3->co);
- VECCOPY(no, efa->n);
- if (efa->v4 == NULL) {
- bevel_displace_vec(vec, v1, v2, v3, d, no);
- VECCOPY(fv2, vec);
- bevel_displace_vec(vec, v2, v3, v1, d, no);
- VECCOPY(fv3, vec);
- bevel_displace_vec(vec, v3, v1, v2, d, no);
- VECCOPY(fv1, vec);
-
- fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no);
-
- glBegin(GL_LINES);
- glVertex3fv(fv1);
- glVertex3fv(fv2);
- glEnd();
- glBegin(GL_LINES);
- glVertex3fv(fv2);
- glVertex3fv(fv3);
- glEnd();
- glBegin(GL_LINES);
- glVertex3fv(fv1);
- glVertex3fv(fv3);
- glEnd();
- } else {
- VECCOPY(v4, efa->v4->co);
- bevel_displace_vec(vec, v4, v1, v2, d, no);
- VECCOPY(fv1, vec);
- bevel_displace_vec(vec, v1, v2, v3, d, no);
- VECCOPY(fv2, vec);
- bevel_displace_vec(vec, v2, v3, v4, d, no);
- VECCOPY(fv3, vec);
- bevel_displace_vec(vec, v3, v4, v1, d, no);
- VECCOPY(fv4, vec);
-
- fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no);
-
- glBegin(GL_LINES);
- glVertex3fv(fv1);
- glVertex3fv(fv2);
- glEnd();
- glBegin(GL_LINES);
- glVertex3fv(fv2);
- glVertex3fv(fv3);
- glEnd();
- glBegin(GL_LINES);
- glVertex3fv(fv3);
- glVertex3fv(fv4);
- glEnd();
- glBegin(GL_LINES);
- glVertex3fv(fv1);
- glVertex3fv(fv4);
- glEnd();
- }
- efa= efa->next;
- }
-}
-
-void bevel_mesh(float bsize, int allfaces)
-{
- EditMesh *em = G.editMesh;
-//#define BEV_DEBUG
-/* Enables debug printfs and assigns material indices: */
-/* 2 = edge quad */
-/* 3 = fill polygon (vertex clusters) */
-
- EditFace *efa, *example; //, *nextvl;
- EditEdge *eed, *eed2;
- EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4;
- float con1, con2, con3;
- //short found4, search;
- //float f1, f2, f3, f4;
- float cent[3], min[3], max[3];
- int a, b, c;
- float limit= 0.001;
-
- waitcursor(1);
-
- removedoublesflag(1, limit);
-
- /* tag all original faces */
- efa= em->faces.first;
- while (efa) {
- if (faceselectedAND(efa, 1)||allfaces) {
- efa->f1= 1;
- efa->v1->f |= 128;
- efa->v2->f |= 128;
- efa->v3->f |= 128;
- if (efa->v4) efa->v4->f |= 128;
- }
- efa->v1->f &= ~64;
- efa->v2->f &= ~64;
- efa->v3->f &= ~64;
- if (efa->v4) efa->v4->f &= ~64;
-
- efa= efa->next;
- }
-
-#ifdef BEV_DEBUG
- fprintf(stderr,"bevel_mesh: split\n");
-#endif
-
- efa= em->faces.first;
- while (efa) {
- if (efa->f1 & 1) {
- efa->f1-= 1;
- v1= addvertlist(efa->v1->co);
- v1->f= efa->v1->f & ~128;
- efa->v1->vn= v1;
-#ifdef __NLA
- v1->totweight = efa->v1->totweight;
- if (efa->v1->totweight){
- v1->dw = MEM_mallocN (efa->v1->totweight * sizeof(MDeformWeight), "deformWeight");
- memcpy (v1->dw, efa->v1->dw, efa->v1->totweight * sizeof(MDeformWeight));
- }
- else
- v1->dw=NULL;
-#endif
- v1= addvertlist(efa->v2->co);
- v1->f= efa->v2->f & ~128;
- efa->v2->vn= v1;
-#ifdef __NLA
- v1->totweight = efa->v2->totweight;
- if (efa->v2->totweight){
- v1->dw = MEM_mallocN (efa->v2->totweight * sizeof(MDeformWeight), "deformWeight");
- memcpy (v1->dw, efa->v2->dw, efa->v2->totweight * sizeof(MDeformWeight));
- }
- else
- v1->dw=NULL;
-#endif
- v1= addvertlist(efa->v3->co);
- v1->f= efa->v3->f & ~128;
- efa->v3->vn= v1;
-#ifdef __NLA
- v1->totweight = efa->v3->totweight;
- if (efa->v3->totweight){
- v1->dw = MEM_mallocN (efa->v3->totweight * sizeof(MDeformWeight), "deformWeight");
- memcpy (v1->dw, efa->v3->dw, efa->v3->totweight * sizeof(MDeformWeight));
- }
- else
- v1->dw=NULL;
-#endif
- if (efa->v4) {
- v1= addvertlist(efa->v4->co);
- v1->f= efa->v4->f & ~128;
- efa->v4->vn= v1;
-#ifdef __NLA
- v1->totweight = efa->v4->totweight;
- if (efa->v4->totweight){
- v1->dw = MEM_mallocN (efa->v4->totweight * sizeof(MDeformWeight), "deformWeight");
- memcpy (v1->dw, efa->v4->dw, efa->v4->totweight * sizeof(MDeformWeight));
- }
- else
- v1->dw=NULL;
-#endif
- }
-
- /* Needs better adaption of creases? */
- addedgelist(efa->e1->v1->vn, efa->e1->v2->vn, efa->e1);
- addedgelist(efa->e2->v1->vn,efa->e2->v2->vn, efa->e2);
- addedgelist(efa->e3->v1->vn,efa->e3->v2->vn, efa->e3);
- if (efa->e4) addedgelist(efa->e4->v1->vn,efa->e4->v2->vn, efa->e4);
-
- if(efa->v4) {
- v1= efa->v1->vn;
- v2= efa->v2->vn;
- v3= efa->v3->vn;
- v4= efa->v4->vn;
- addfacelist(v1, v2, v3, v4, efa);
- } else {
- v1= efa->v1->vn;
- v2= efa->v2->vn;
- v3= efa->v3->vn;
- addfacelist(v1, v2, v3, 0, efa);
- }
-
- efa= efa-> next;
- } else {
- efa= efa->next;
- }
- }
-
- delfaceflag(128);
-
- /* tag all faces for shrink*/
- efa= em->faces.first;
- while (efa) {
- if (faceselectedAND(efa, 1)||allfaces) {
- efa->f1= 2;
- }
- efa= efa->next;
- }
-
-#ifdef BEV_DEBUG
- fprintf(stderr,"bevel_mesh: make edge quads\n");
-#endif
-
- /* find edges that are on each other and make quads between them */
-
- eed= em->edges.first;
- while(eed) {
- eed->f= eed->f1= 0;
- if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces) eed->f1 |= 4; /* original edges */
- eed->vn= 0;
- eed= eed->next;
- }
-
- eed= em->edges.first;
- while (eed) {
- if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) {
- eed2= em->edges.first;
- while (eed2) {
- if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) {
- if (
- (eed->v1 != eed2->v1) &&
- (eed->v1 != eed2->v2) &&
- (eed->v2 != eed2->v1) &&
- (eed->v2 != eed2->v2) && (
- ( VecCompare(eed->v1->co, eed2->v1->co, limit) &&
- VecCompare(eed->v2->co, eed2->v2->co, limit) ) ||
- ( VecCompare(eed->v1->co, eed2->v2->co, limit) &&
- VecCompare(eed->v2->co, eed2->v1->co, limit) ) ) )
- {
-
-#ifdef BEV_DEBUG
- fprintf(stderr, "bevel_mesh: edge quad\n");
-#endif
-
- eed->f1 |= 2; /* these edges are finished */
- eed2->f1 |= 2;
-
- example= NULL;
- efa= em->faces.first; /* search example face (for mat_nr, ME_SMOOTH, ...) */
- while (efa) {
- if ( (efa->e1 == eed) ||
- (efa->e2 == eed) ||
- (efa->e3 == eed) ||
- (efa->e4 && (efa->e4 == eed)) ) {
- example= efa;
- efa= NULL;
- }
- if (efa) efa= efa->next;
- }
-
- neweve[0]= eed->v1; neweve[1]= eed->v2;
- neweve[2]= eed2->v1; neweve[3]= eed2->v2;
-
- if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
- efa= NULL;
-
- if (VecCompare(eed->v1->co, eed2->v2->co, limit)) {
- efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example);
- } else {
- efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example);
- }
-
- if(efa) {
- float inp;
- CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
- inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
- if(inp < 0.0) flipface(efa);
-#ifdef BEV_DEBUG
- efa->mat_nr= 1;
-#endif
- } else fprintf(stderr,"bevel_mesh: error creating face\n");
- }
- eed2= NULL;
- }
- }
- if (eed2) eed2= eed2->next;
- }
- }
- eed= eed->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- eed->f= eed->f1= 0;
- eed->f1= 0;
- eed->v1->f1 &= ~1;
- eed->v2->f1 &= ~1;
- eed->vn= 0;
- eed= eed->next;
- }
-
-#ifdef BEV_DEBUG
- fprintf(stderr,"bevel_mesh: find clusters\n");
-#endif
-
- /* Look for vertex clusters */
-
- eve= em->verts.first;
- while (eve) {
- eve->f &= ~(64|128);
- eve->vn= NULL;
- eve= eve->next;
- }
-
- /* eve->f: 128: first vertex in a list (->vn) */
- /* 64: vertex is in a list */
-
- eve= em->verts.first;
- while (eve) {
- eve2= em->verts.first;
- eve3= NULL;
- while (eve2) {
- if ((eve2 != eve) && ((eve2->f & (64|128))==0)) {
- if (VecCompare(eve->co, eve2->co, limit)) {
- if ((eve->f & (128|64)) == 0) {
- /* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */
- eve->f |= 128;
- eve->vn= eve2;
- eve3= eve2;
- } else if ((eve->f & 64) == 0) {
- /* fprintf(stderr," *\n"); */
- if (eve3) eve3->vn= eve2;
- eve2->f |= 64;
- eve3= eve2;
- }
- }
- }
- eve2= eve2->next;
- if (!eve2) {
- if (eve3) eve3->vn= NULL;
- }
- }
- eve= eve->next;
- }
-
-#ifdef BEV_DEBUG
- fprintf(stderr,"bevel_mesh: shrink faces\n");
-#endif
-
- bevel_shrink_faces(bsize, 2);
-
-#ifdef BEV_DEBUG
- fprintf(stderr,"bevel_mesh: fill clusters\n");
-#endif
-
- /* Make former vertex clusters faces */
-
- eve= em->verts.first;
- while (eve) {
- eve->f &= ~64;
- eve= eve->next;
- }
-
- eve= em->verts.first;
- while (eve) {
- if (eve->f & 128) {
- eve->f &= ~128;
- a= 0;
- neweve[a]= eve;
- eve2= eve->vn;
- while (eve2) {
- a++;
- neweve[a]= eve2;
- eve2= eve2->vn;
- }
- a++;
- efa= NULL;
- if (a>=3) {
- example= NULL;
- efa= em->faces.first; /* search example face */
- while (efa) {
- if ( (efa->v1 == neweve[0]) ||
- (efa->v2 == neweve[0]) ||
- (efa->v3 == neweve[0]) ||
- (efa->v4 && (efa->v4 == neweve[0])) ) {
- example= efa;
- efa= NULL;
- }
- if (efa) efa= efa->next;
- }
-#ifdef BEV_DEBUG
- fprintf(stderr,"bevel_mesh: Making %d-gon\n", a);
-#endif
- if (a>4) {
- cent[0]= cent[1]= cent[2]= 0.0;
- INIT_MINMAX(min, max);
- for (b=0; b<a; b++) {
- VecAddf(cent, cent, neweve[b]->co);
- DO_MINMAX(neweve[b]->co, min, max);
- }
- cent[0]= (min[0]+max[0])/2;
- cent[1]= (min[1]+max[1])/2;
- cent[2]= (min[2]+max[2])/2;
- eve2= addvertlist(cent);
- eve2->f |= 1;
- eed= em->edges.first;
- while (eed) {
- c= 0;
- for (b=0; b<a; b++)
- if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++;
- if (c==2) {
- if(exist_face(eed->v1, eed->v2, eve2, 0)==0) {
- efa= addfacelist(eed->v1, eed->v2, eve2, 0, example);
-#ifdef BEV_DEBUG
- efa->mat_nr= 2;
-#endif
- }
- }
- eed= eed->next;
- }
- } else if (a==4) {
- if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
- con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co);
- con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co);
- con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co);
- if(con1>=con2 && con1>=con3)
- efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example);
- else if(con2>=con1 && con2>=con3)
- efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example);
- else
- efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], example);
- }
- }
- else if (a==3) {
- if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0)
- efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, example);
- }
- if(efa) {
- float inp;
- CalcNormFloat(neweve[0]->co, neweve[1]->co, neweve[2]->co, efa->n);
- inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
- if(inp < 0.0) flipface(efa);
-#ifdef BEV_DEBUG
- efa->mat_nr= 2;
-#endif
- }
- }
- }
- eve= eve->next;
- }
-
- eve= em->verts.first;
- while (eve) {
- eve->f1= 0;
- eve->f &= ~(128|64);
- eve->vn= NULL;
- eve= eve->next;
- }
-
- recalc_editnormals();
- waitcursor(0);
- countall();
- allqueue(REDRAWVIEW3D, 0);
- makeDispList(G.obedit);
-
- removedoublesflag(1, limit);
-
-#undef BEV_DEBUG
-}
-
-void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
-{
- float d;
- short nr;
-
- d= bsize;
- for (nr=0; nr<recurs; nr++) {
- bevel_mesh(d, allfaces);
- if (nr==0) d /= 3; else d /= 2;
- }
-}
-
-void bevel_menu()
-{
- char Finished = 0, Canceled = 0, str[100], Recalc = 0;
- short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr;
- float vec[3], d, drawd=0.0, centre[3], fac = 1;
-
- getmouseco_areawin(mval);
- oval[0] = mval[0]; oval[1] = mval[1];
-
- // Silly hackish code to initialise the variable (warning if not done)
- // while still drawing in the first iteration (and without using another variable)
- curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
-
- window_to_3d(centre, mval[0], mval[1]);
-
- if(button(&recurs, 1, 4, "Recursion:")==0) return;
-
- for (nr=0; nr<recurs-1; nr++) {
- if (nr==0) fac += 1.0/3.0; else fac += 1.0/(3 * nr * 2.0);
- }
-
- SetBlenderCursor(SYSCURSOR);
-
- while (Finished == 0)
- {
- getmouseco_areawin(mval);
- if (mval[0] != curval[0] || mval[1] != curval[1] || (Recalc == 1))
- {
- Recalc = 0;
- curval[0] = mval[0];
- curval[1] = mval[1];
-
- window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]);
- d = Normalise(vec) / 10;
-
-
- drawd = d * fac;
- if (G.qual & LR_CTRLKEY)
- drawd = (float) floor(drawd * 10.0)/10.0;
- if (G.qual & LR_SHIFTKEY)
- drawd /= 10;
-
- /*------------- Preview lines--------------- */
-
- /* uses callback mechanism to draw it all in current area */
- scrarea_do_windraw(curarea);
-
- /* set window matrix to perspective, default an area returns with buttons transform */
- persp(PERSP_VIEW);
- /* make a copy, for safety */
- glPushMatrix();
- /* multiply with the object transformation */
- mymultmatrix(G.obedit->obmat);
-
- glColor3ub(255, 255, 0);
-
- // PREVIEW CODE GOES HERE
- bevel_shrink_draw(drawd, 2);
-
- /* restore matrix transform */
- glPopMatrix();
-
- sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd);
- headerprint(str);
-
- /* this also verifies other area/windows for clean swap */
- screen_swapbuffers();
-
- persp(PERSP_WIN);
-
- glDrawBuffer(GL_FRONT);
-
- BIF_ThemeColor(TH_WIRE);
-
- setlinestyle(3);
- glBegin(GL_LINE_STRIP);
- glVertex2sv(mval);
- glVertex2sv(oval);
- glEnd();
- setlinestyle(0);
-
- persp(PERSP_VIEW);
- glFlush(); // flush display for frontbuffer
- glDrawBuffer(GL_BACK);
- }
- while(qtest()) {
- unsigned 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 && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)){
- if (event==RIGHTMOUSE || event==ESCKEY)
- Canceled = 1;
- Finished = 1;
- }
- else if (val && event==SPACEKEY) {
- if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) {
- drawd = d * fac;
- Finished = 1;
- }
- }
- else if (val) {
- /* On any other keyboard event, recalc */
- Recalc = 1;
- }
-
- }
- }
- if (Canceled==0) {
- SetBlenderCursor(BC_WAITCURSOR);
- undo_push_mesh("Bevel");
- bevel_mesh_recurs(drawd/fac, recurs, 1);
- righthandfaces(1);
- SetBlenderCursor(SYSCURSOR);
- }
-}
-
-void select_non_manifold(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- /* Selects isolated verts, and edges that do not have 2 neighboring
- * faces
- */
-
-
- 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->f1 != 2) {
- if (!eed->v1->h) eed->v1->f |= 1;
- if (!eed->v2->h) eed->v2->f |= 1;
- }
- eed= eed->next;
- }
-
- /* select isolated verts */
- eve= em->verts.first;
- while(eve) {
- if (eve->f1 == 0) {
- if (!eve->h) eve->f |= 1;
- }
- eve= eve->next;
- }
-
- countall();
- addqueue(curarea->win, REDRAW, 0);
-
-}
-
-void select_more(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- EditEdge *eed;
-
- eve= em->verts.first;
- while(eve) {
- eve->f1 = 0;
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- if (eed->v1->f & 1)
- eed->v2->f1 = 1;
- if (eed->v2->f & 1)
- eed->v1->f1 = 1;
-
- eed= eed->next;
- }
-
- eve= em->verts.first;
- while(eve) {
- if (eve->f1 == 1)
- if (!eve->h) eve->f |= 1;
-
- eve= eve->next;
- }
-
- countall();
- addqueue(curarea->win, REDRAW, 0);
-}
-
-void select_less(void)
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- /* eve->f1 & 1 => isolated */
- /* eve->f1 & 2 => on an edge */
- /* eve->f1 & 4 => shares edge with a deselected vert */
- /* eve->f1 & 8 => at most one neighbor */
-
- eve= em->verts.first;
- while(eve) {
- /* assume vert is isolated unless proven otherwise, */
- /* assume at most one neighbor too */
- eve->f1 = 1 | 8;
-
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- /* this will count how many faces are connected to
- * this edge */
- eed->f1= 0;
-
- /* if vert wasn't isolated, it now has more than one neighbor */
- if (~eed->v1->f1 & 1) eed->v1->f1 &= ~8;
- if (~eed->v2->f1 & 1) eed->v2->f1 &= ~8;
-
- /* verts on edge are clearly not isolated */
- eed->v1->f1 &= ~1;
- eed->v2->f1 &= ~1;
-
- /* if one of the verts on the edge is deselected,
- * deselect the other */
- if ( !(eed->v1->h) && (~eed->v1->f & 1) )
- eed->v2->f1 |= 4;
- if ( !(eed->v2->h) && (~eed->v2->f & 1) )
- eed->v1->f1 |= 4;
-
- 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;
- }
-
- eed= em->edges.first;
- while(eed) {
- /* if the edge has only one neighboring face, then
- * deselect attached verts */
- if (eed->f1 == 1) {
- eed->v1->f1 |= 2;
- eed->v2->f1 |= 2;
- }
-
- eed= eed->next;
- }
-
- /* deselect verts */
- eve= em->verts.first;
- while(eve) {
- if (eve->f1) {
- eve->f &= ~1;
- }
-
- eve= eve->next;
- }
-
- countall();
- allqueue(REDRAWVIEW3D, 0);
-}
-
-
-void selectrandom_mesh(void) /* randomly selects a user-set % of vertices */
-{
- EditMesh *em = G.editMesh;
- EditVert *eve;
- int newsel = 0; /* to decide whether to redraw or not */
- short randfac = 50;
-
- if(G.obedit==0) return;
-
- /* Get the percentage of vertices to randomly select as 'randfac' */
- if(button(&randfac,0, 100,"Percentage:")==0) return;
-
- if(G.obedit->lay & G.vd->lay) {
- eve= em->verts.first;
- while(eve) {
- BLI_srand( BLI_rand() ); /* random seed */
- if ( (BLI_frand() * 100) < randfac) {
- eve->f |= SELECT;
- newsel = 1;
- } else {
- /* Deselect other vertices
- *
- * - Commenting this out makes it add to the selection,
- * rather than replace it.
- * eve->f &= ~SELECT;
- */
- }
- eve= eve->next;
- }
- countall();
- allqueue(REDRAWVIEW3D, 0);
- }
-}
-
-short edgeFaces(EditEdge *e){
- EditMesh *em = G.editMesh;
- 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;
-}
-
-/* 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(EditEdge* e1, EditEdge* e2)
-{
- EditMesh *em = G.editMesh;
- 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;
-}
-/* This function selects a vertex loop based on a each succesive edge having a valance of 4
- and not sharing a face with the previous edge */
-
-void vertex_loop_select()
-{
- EditMesh *em = G.editMesh;
- EditVert *v1=NULL,*v2=NULL;
- EditEdge *search=NULL,*startEdge=NULL,*valSearch = NULL,*nearest = NULL,*compEdge;
- EditEdge *EdgeVal[5] = {NULL,NULL,NULL,NULL,NULL};
- short numEdges=0,curEdge = 0,looking = 1,edgeValCount = 0,i=0,looped = 0,choosing = 1,event,noloop=0,cancel=0, val;
- short protect = 0;
- short mvalo[2] = {0,0}, mval[2];
-
- undo_push_mesh("Select Vertex Loop");
- SetBlenderCursor(BC_VLOOPCURSOR);
- for(search=em->edges.first;search;search=search->next)
- numEdges++;
-
- /* start with v1 and go in one direction. */
- while(choosing){
- getmouseco_areawin(mval);
- if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
-
- mvalo[0] = mval[0];
- mvalo[1] = mval[1];
-
- scrarea_do_windraw(curarea);
- nearest = findnearestedge();
- if (nearest && edgeFaces(nearest)==2) {
- for(search = em->edges.first;search;search=search->next)
- search->f &= ~32;
-
- compEdge = startEdge = nearest;
- nearest->f |= 32;
- curEdge = 0;
- v1 = startEdge->v1;
- v2 = startEdge->v2;
- looking = 1;
- while(looking){
- if(protect++ > numEdges) break;
- if(edgeFaces(compEdge) != 2) break;
- /*Find Edges that have v1*/
- edgeValCount = -1;
- EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
-
- for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
- if(valSearch->v1 == v1 || valSearch->v2 == v1){
- if(valSearch != compEdge){
- if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
- if(edgeFaces(valSearch) == 2){
- edgeValCount++;
- EdgeVal[edgeValCount] = valSearch;
- }
- }
- }
- }
- if(edgeValCount == 3)break;
- }
- /* Check that there was a valance of 4*/
- if(edgeValCount != 2){
- noloop = 1;
- looking = 0;
- break;
- }
- else{
- /* There were 3 edges, so find the one that does not share the previous edge */
- for(i=0;i<3;i++){
- if(sharesFace(compEdge,EdgeVal[i]) == 0){
- /* We went all the way around the loop */
- if(EdgeVal[i] == nearest){
- looking = 0;
- looped = 1;
- break;
- }
- else{
- /* we are still in the loop, so add the next edge*/
- curEdge++;
- EdgeVal[i]->f |= 32;
- compEdge = EdgeVal[i];
- if(compEdge->v1 == v1)
- v1 = compEdge->v2;
- else
- v1 = compEdge->v1;
- }
- }
- }
- }
- }
- compEdge = nearest;
- looking = 1;
- protect = 0;
- while(looking/* && !looped*/){
- if(protect++ > numEdges) break;
- if(edgeFaces(compEdge) != 2) break;
- /*Find Edges that have v1*/
- edgeValCount = -1;
- EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
-
- for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
- if(valSearch->v1 == v2 || valSearch->v2 == v2){
- if(valSearch != compEdge){
- if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
- if(edgeFaces(valSearch) == 2){
- edgeValCount++;
- EdgeVal[edgeValCount] = valSearch;
- }
- }
- }
- }
- if(edgeValCount == 3)break;
- }
- /* Check that there was a valance of 4*/
- if(edgeValCount != 2){
- noloop = 1;
- looking = 0;
- break;
- }
- else{
- /* There were 3 edges, so find the one that does not share the previous edge */
- for(i=0;i<3;i++){
- if(sharesFace(compEdge,EdgeVal[i]) == 0){
- /* We went all the way around the loop */
- if(EdgeVal[i] == nearest){
- looking = 0;
- looped = 1;
- break;
- }
- else{
- /* we are still in the loop, so add the next edge*/
- curEdge++;
- EdgeVal[i]->f |= 32;
- compEdge = EdgeVal[i];
- if(compEdge->v1 == v2)
- v2 = compEdge->v2;
- else
- v2 = compEdge->v1;
- }
- }
- }
- }
- }
- /* set up for opengl drawing in the 3d window */
- persp(PERSP_VIEW);
- glPushMatrix();
- mymultmatrix(G.obedit->obmat);
- glColor3ub(0, 255, 255);
- for(search = em->edges.first;search;search= search->next){
- if(search->f & 32){
- glBegin(GL_LINES);
- glVertex3f(search->v1->co[0],search->v1->co[1],search->v1->co[2]);
- glVertex3f(search->v2->co[0],search->v2->co[1],search->v2->co[2]);
- glEnd();
- }
- }
-
- glPopMatrix();
- }
- }
-
- screen_swapbuffers();
-
- while(qtest())
- {
- val=0;
- event= extern_qread(&val);
- if(val && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE))
- {
- if (nearest==NULL)
- cancel = 1;
- choosing=0;
- break;
- }
- if(val && (event==ESCKEY || event==RIGHTMOUSE ))
- {
- choosing=0;
- cancel = 1;
- break;
- }
- if(val && (event==BKEY && G.qual==LR_ALTKEY ))
- {
-
- SetBlenderCursor(SYSCURSOR);
- loopoperations(LOOP_SELECT);
- return;
- }
- }
- }
- if(!cancel){
- /* If this is a unmodified select, clear the selection */
- if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
- for(search = em->edges.first;search;search= search->next){
- search->v1->f &= !1;
- search->v2->f &= !1;
- }
- }
- /* Alt was not pressed, so add to the selection */
- if(!(G.qual & LR_ALTKEY)){
- for(search = em->edges.first;search;search= search->next){
- if(search->f & 32){
- search->v1->f |= 1;
- search->v2->f |= 1;
- }
- search->f &= ~32;
- }
- }
- /* alt was pressed, so subtract from the selection */
- else
- {
- for(search = em->edges.first;search;search= search->next){
- if(search->f & 32){
- search->v1->f &= !1;
- search->v2->f &= !1;
- }
- search->f &= ~32;
- }
- }
- }
- else
- undo_pop_mesh(1);
- addqueue(curarea->win, REDRAW, 1);
- SetBlenderCursor(SYSCURSOR);
- return;
-}
-
-void editmesh_select_by_material(int index)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa;
-
- for (efa=em->faces.first; efa; efa= efa->next) {
- if (efa->mat_nr==index) {
- if(efa->v1->h==0) efa->v1->f |= 1;
- if(efa->v2->h==0) efa->v2->f |= 1;
- if(efa->v3->h==0) efa->v3->f |= 1;
- if(efa->v4 && efa->v4->h==0) efa->v4->f |= 1;
- }
- }
-}
-
-void editmesh_deselect_by_material(int index)
-{
- EditMesh *em = G.editMesh;
- EditFace *efa;
-
- for (efa=em->faces.first; efa; efa= efa->next) {
- if (efa->mat_nr==index) {
- if(efa->v1->h==0) efa->v1->f &= ~1;
- if(efa->v2->h==0) efa->v2->f &= ~1;
- if(efa->v3->h==0) efa->v3->f &= ~1;
- if(efa->v4 && efa->v4->h==0) efa->v4->f &= ~1;
- }
- }
-}
-
-void editmesh_mark_seam(int clear)
-{
- EditMesh *em= G.editMesh;
- EditEdge *eed;
- Mesh *me= G.obedit->data;
-
- /* auto-enable seams drawing */
- if(clear==0) {
- if(!(G.f & G_DRAWSEAMS)) {
- G.f |= G_DRAWSEAMS;
- allqueue(REDRAWBUTSEDIT, 0);
- }
- if(!me->medge)
- me->medge= MEM_callocN(sizeof(MEdge), "fake mesh edge");
- }
-
- if(clear) {
- eed= em->edges.first;
- while(eed) {
- if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) {
- eed->seam = 0;
- }
- eed= eed->next;
- }
- }
- else {
- eed= em->edges.first;
- while(eed) {
- if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) {
- eed->seam = 1;
- }
- eed= eed->next;
- }
- }
-
- allqueue(REDRAWVIEW3D, 0);
-}
-
-void Edge_Menu() {
- short ret;
-
- ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edges %x3");
-
- switch(ret)
- {
- case 1:
- editmesh_mark_seam(0);
- break;
- case 2:
- editmesh_mark_seam(1);
- break;
- case 3:
- edge_rotate_selected();
- break;
- }
-}
-
diff --git a/source/blender/src/editmesh_add.c b/source/blender/src/editmesh_add.c
new file mode 100644
index 00000000000..2c8d1b9613a
--- /dev/null
+++ b/source/blender/src/editmesh_add.c
@@ -0,0 +1,699 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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 NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_graphics.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_editobject.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "editmesh.h"
+
+static float icovert[12][3] = {
+ {0,0,-200},
+ {144.72, -105.144,-89.443},
+ {-55.277, -170.128,-89.443},
+ {-178.885,0,-89.443},
+ {-55.277,170.128,-89.443},
+ {144.72,105.144,-89.443},
+ {55.277,-170.128,89.443},
+ {-144.72,-105.144,89.443},
+ {-144.72,105.144,89.443},
+ {55.277,170.128,89.443},
+ {178.885,0,89.443},
+ {0,0,200}
+};
+static short icoface[20][3] = {
+ {1,0,2},
+ {1,0,5},
+ {2,0,3},
+ {3,0,4},
+ {4,0,5},
+ {1,5,10},
+ {2,1,6},
+ {3,2,7},
+ {4,3,8},
+ {5,4,9},
+ {10,1,6},
+ {6,2,7},
+ {7,3,8},
+ {8,4,9},
+ {9,5,10},
+ {6,10,11},
+ {7,6,11},
+ {8,7,11},
+ {9,8,11},
+ {10,9,11}
+};
+
+void addvert_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1=0;
+ float *curs, mat[3][3],imat[3][3];
+
+ TEST_EDITMESH
+
+ Mat3CpyMat4(mat, G.obedit->obmat);
+ Mat3Inv(imat, mat);
+
+ v1= em->verts.first;
+ while(v1) {
+ if(v1->f & 1) break;
+ v1= v1->next;
+ }
+ eve= v1; /* prevent there are more selected */
+ while(eve) {
+ eve->f&= ~1;
+ eve= eve->next;
+ }
+
+ eve= addvertlist(0);
+
+ curs= give_cursor();
+ VECCOPY(eve->co, curs);
+ eve->xs= G.vd->mx;
+ eve->ys= G.vd->my;
+ VecSubf(eve->co, eve->co, G.obedit->obmat[3]);
+
+ Mat3MulVecfl(imat, eve->co);
+ eve->f= 1;
+
+ if(v1) {
+ addedgelist(v1, eve, NULL);
+ v1->f= 0;
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+
+ while(get_mbut()&R_MOUSE);
+
+}
+
+void addedgeface_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *neweve[4];
+ EditFace *efa;
+ float con1, con2, con3;
+ short aantal=0;
+
+ if( (G.vd->lay & G.obedit->lay)==0 ) return;
+
+ /* how many selected ? */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ aantal++;
+ if(aantal>4) break;
+ neweve[aantal-1]= eve;
+ }
+ eve= eve->next;
+ }
+ if(aantal==2) {
+ addedgelist(neweve[0], neweve[1], NULL);
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+ return;
+ }
+ if(aantal<2 || aantal>4) {
+ error("Incorrect number of vertices to make edge/face");
+ return;
+ }
+
+ efa= NULL; // check later
+
+ if(aantal==3) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0) {
+
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, NULL);
+
+ }
+ else error("The selected vertices already form a face");
+ }
+ else if(aantal==4) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+
+ con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co);
+ con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co);
+ con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co);
+
+ if(con1>=con2 && con1>=con3)
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL);
+ else if(con2>=con1 && con2>=con3)
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL);
+ else
+ efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL);
+
+ }
+ else error("The selected vertices already form a face");
+ }
+
+ if(efa) { // now we're calculating direction of normal
+ float inp;
+ /* dot product view mat with normal, should give info! */
+
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+
+ if(inp < 0.0) flipface(efa);
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+void adduplicateflag(int flag)
+{
+ EditMesh *em = G.editMesh;
+ /* old verts have flag 128 set, and flag 'flag' cleared
+ new verts have flag 'flag' set */
+ EditVert *eve, *v1, *v2, *v3, *v4;
+ EditEdge *eed;
+ EditFace *efa;
+
+ /* vertices first */
+ eve= em->verts.last;
+ while(eve) {
+ eve->f&= ~128;
+ if(eve->f & flag) {
+ v1= addvertlist(eve->co);
+ v1->f= eve->f;
+ eve->f-= flag;
+ eve->f|= 128;
+ eve->vn= v1;
+#ifdef __NLA
+ /* >>>>> FIXME: Copy deformation weight ? */
+ v1->totweight = eve->totweight;
+ if (eve->totweight){
+ v1->dw = MEM_mallocN (eve->totweight * sizeof(MDeformWeight), "deformWeight");
+ memcpy (v1->dw, eve->dw, eve->totweight * sizeof(MDeformWeight));
+ }
+ else
+ v1->dw=NULL;
+#endif
+ }
+ eve= eve->prev;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ if( (eed->v1->f & 128) && (eed->v2->f & 128) ) {
+ v1= eed->v1->vn;
+ v2= eed->v2->vn;
+ addedgelist(v1, v2, eed);
+ }
+ eed= eed->next;
+ }
+
+ /* then dupicate faces */
+ efa= em->faces.first;
+ while(efa) {
+ if( (efa->v1->f & 128) && (efa->v2->f & 128) && (efa->v3->f & 128) ) {
+ if(efa->v4) {
+ if(efa->v4->f & 128) {
+ v1= efa->v1->vn;
+ v2= efa->v2->vn;
+ v3= efa->v3->vn;
+ v4= efa->v4->vn;
+ addfacelist(v1, v2, v3, v4, efa);
+ }
+ }
+ else {
+ v1= efa->v1->vn;
+ v2= efa->v2->vn;
+ v3= efa->v3->vn;
+ addfacelist(v1, v2, v3, 0, efa);
+ }
+ }
+ efa= efa->next;
+ }
+}
+
+void adduplicate_mesh(void)
+{
+
+ TEST_EDITMESH
+
+ waitcursor(1);
+ undo_push_mesh("Duplicate");
+ adduplicateflag(1);
+ waitcursor(0);
+ countall(); /* for G.totvert in calc_meshverts() */
+ transform('d');
+}
+
+
+
+void add_primitiveMesh(int type)
+{
+ EditMesh *em = G.editMesh;
+ Mesh *me;
+ EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
+ float *curs, d, dia, phi, phid, cent[3], vec[3], imat[3][3], mat[3][3];
+ float q[4], cmat[3][3];
+ static short tot=32, seg=32, subdiv=2;
+ short a, b, ext=0, fill=0, totoud, newob=0;
+
+ if(G.scene->id.lib) return;
+
+ /* this function also comes from an info window */
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+ if(G.vd==0) return;
+
+ /* if editmode exists for other type, it exits */
+ check_editmode(OB_MESH);
+
+ if(G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT)) {
+ G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT);
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ }
+
+ /* if no obedit: new object and enter editmode */
+ if(G.obedit==NULL) {
+ /* add_object actually returns an object ! :-)
+ But it also stores the added object struct in
+ G.scene->basact->object (BASACT->object) */
+
+ add_object_draw(OB_MESH);
+
+ G.obedit= BASACT->object;
+
+ where_is_object(G.obedit);
+
+ make_editMesh();
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ newob= 1;
+ }
+ me= G.obedit->data;
+
+ /* deselectall */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) eve->f&= ~1;
+ eve= eve->next;
+ }
+
+ totoud= tot; /* store, and restore when cube/plane */
+
+ /* imat and centre and size */
+ Mat3CpyMat4(mat, G.obedit->obmat);
+
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
+
+ if(type!= 11) {
+ Mat3CpyMat4(imat, G.vd->viewmat);
+ Mat3MulVecfl(imat, cent);
+ Mat3MulMat3(cmat, imat, mat);
+ Mat3Inv(imat,cmat);
+ } else {
+ Mat3Inv(imat, mat);
+ }
+
+ /* ext==extrudeflag, tot==amount of vertices in basis */
+
+ switch(type) {
+ case 0: /* plane */
+ tot= 4;
+ ext= 0;
+ fill= 1;
+ if(newob) rename_id((ID *)G.obedit, "Plane");
+ if(newob) rename_id((ID *)me, "Plane");
+ break;
+ case 1: /* cube */
+ tot= 4;
+ ext= 1;
+ fill= 1;
+ if(newob) rename_id((ID *)G.obedit, "Cube");
+ if(newob) rename_id((ID *)me, "Cube");
+ break;
+ case 4: /* circle */
+ if(button(&tot,3,100,"Vertices:")==0) return;
+ ext= 0;
+ fill= 0;
+ if(newob) rename_id((ID *)G.obedit, "Circle");
+ if(newob) rename_id((ID *)me, "Circle");
+ break;
+ case 5: /* cylinder */
+ if(button(&tot,3,100,"Vertices:")==0) return;
+ ext= 1;
+ fill= 1;
+ if(newob) rename_id((ID *)G.obedit, "Cylinder");
+ if(newob) rename_id((ID *)me, "Cylinder");
+ break;
+ case 6: /* tube */
+ if(button(&tot,3,100,"Vertices:")==0) return;
+ ext= 1;
+ fill= 0;
+ if(newob) rename_id((ID *)G.obedit, "Tube");
+ if(newob) rename_id((ID *)me, "Tube");
+ break;
+ case 7: /* cone */
+ if(button(&tot,3,100,"Vertices:")==0) return;
+ ext= 0;
+ fill= 1;
+ if(newob) rename_id((ID *)G.obedit, "Cone");
+ if(newob) rename_id((ID *)me, "Cone");
+ break;
+ case 10: /* grid */
+ if(button(&tot,2,100,"X res:")==0) return;
+ if(button(&seg,2,100,"Y res:")==0) return;
+ if(newob) rename_id((ID *)G.obedit, "Grid");
+ if(newob) rename_id((ID *)me, "Grid");
+ break;
+ case 11: /* UVsphere */
+ if(button(&seg,3,100,"Segments:")==0) return;
+ if(button(&tot,3,100,"Rings:")==0) return;
+ if(newob) rename_id((ID *)G.obedit, "Sphere");
+ if(newob) rename_id((ID *)me, "Sphere");
+ break;
+ case 12: /* Icosphere */
+ if(button(&subdiv,1,5,"Subdivision:")==0) return;
+ if(newob) rename_id((ID *)G.obedit, "Sphere");
+ if(newob) rename_id((ID *)me, "Sphere");
+ break;
+ case 13: /* Monkey */
+ if(newob) rename_id((ID *)G.obedit, "Suzanne");
+ if(newob) rename_id((ID *)me, "Suzanne");
+ break;
+ }
+
+ dia= sqrt(2.0)*G.vd->grid;
+ d= -G.vd->grid;
+ phid= 2*M_PI/tot;
+ phi= .25*M_PI;
+
+
+ if(type<10) { /* all types except grid, sphere... */
+ if(ext==0 && type!=7) d= 0;
+
+ /* vertices */
+ vtop= vdown= v1= v2= 0;
+ for(b=0; b<=ext; b++) {
+ for(a=0; a<tot; a++) {
+
+ vec[0]= cent[0]+dia*sin(phi);
+ vec[1]= cent[1]+dia*cos(phi);
+ vec[2]= cent[2]+d;
+
+ Mat3MulVecfl(imat, vec);
+ eve= addvertlist(vec);
+ eve->f= 1;
+ if(a==0) {
+ if(b==0) v1= eve;
+ else v2= eve;
+ }
+ phi+=phid;
+ }
+ d= -d;
+ }
+ /* centre vertices */
+ if(fill && type>1) {
+ VECCOPY(vec,cent);
+ vec[2]-= -d;
+ Mat3MulVecfl(imat,vec);
+ vdown= addvertlist(vec);
+ if(ext || type==7) {
+ VECCOPY(vec,cent);
+ vec[2]-= d;
+ Mat3MulVecfl(imat,vec);
+ vtop= addvertlist(vec);
+ }
+ } else {
+ vdown= v1;
+ vtop= v2;
+ }
+ if(vtop) vtop->f= 1;
+ if(vdown) vdown->f= 1;
+
+ /* top and bottom face */
+ if(fill) {
+ if(tot==4 && (type==0 || type==1)) {
+ v3= v1->next->next;
+ if(ext) v4= v2->next->next;
+
+ addfacelist(v3, v1->next, v1, v3->next, NULL);
+ if(ext) addfacelist(v2, v2->next, v4, v4->next, NULL);
+
+ }
+ else {
+ v3= v1;
+ v4= v2;
+ for(a=1; a<tot; a++) {
+ addfacelist(vdown, v3, v3->next, 0, NULL);
+ v3= v3->next;
+ if(ext) {
+ addfacelist(vtop, v4, v4->next, 0, NULL);
+ v4= v4->next;
+ }
+ }
+ if(type>1) {
+ addfacelist(vdown, v3, v1, 0, NULL);
+ if(ext) addfacelist(vtop, v4, v2, 0, NULL);
+ }
+ }
+ }
+ else if(type==4) { /* we need edges for a circle */
+ v3= v1;
+ for(a=1;a<tot;a++) {
+ addedgelist(v3, v3->next, NULL);
+ v3= v3->next;
+ }
+ addedgelist(v3, v1, NULL);
+ }
+ /* side faces */
+ if(ext) {
+ v3= v1;
+ v4= v2;
+ for(a=1; a<tot; a++) {
+ addfacelist(v3, v3->next, v4->next, v4, NULL);
+ v3= v3->next;
+ v4= v4->next;
+ }
+ addfacelist(v3, v1, v2, v4, NULL);
+ }
+ else if(type==7) { /* cone */
+ v3= v1;
+ for(a=1; a<tot; a++) {
+ addfacelist(vtop, v3->next, v3, 0, NULL);
+ v3= v3->next;
+ }
+ addfacelist(vtop, v1, v3, 0, NULL);
+ }
+
+ if(type<2) tot= totoud;
+
+ }
+ else if(type==10) { /* grid */
+ /* clear flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f= 0;
+ eve= eve->next;
+ }
+ dia= G.vd->grid;
+ /* one segment first: de X as */
+ phi= -1.0;
+ phid= 2.0/((float)tot-1);
+ for(a=0;a<tot;a++) {
+ vec[0]= cent[0]+dia*phi;
+ vec[1]= cent[1]- dia;
+ vec[2]= cent[2];
+ Mat3MulVecfl(imat,vec);
+ eve= addvertlist(vec);
+ eve->f= 1+2+4;
+ if (a) addedgelist(eve->prev, eve, NULL);
+ phi+=phid;
+ }
+ /* extrude and translate */
+ vec[0]= vec[2]= 0.0;
+ vec[1]= dia*phid;
+ Mat3MulVecfl(imat, vec);
+ for(a=0;a<seg-1;a++) {
+ extrudeflag(2,0);
+ translateflag(2, vec);
+ }
+ }
+ else if(type==11) { /* UVsphere */
+ float tmat[3][3];
+
+ /* 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]= cent[0]+dia*sin(phi);
+ vec[1]= cent[1];
+ vec[2]= cent[2]+dia*cos(phi);
+ Mat3MulVecfl(imat,vec);
+ eve= addvertlist(vec);
+ eve->f= 1+2+4;
+ if(a==0) v1= eve;
+ else addedgelist(eve->prev, eve, NULL);
+ phi+= phid;
+ }
+
+ /* extrude and rotate */
+ phi= M_PI/seg;
+ q[0]= cos(phi);
+ q[3]= sin(phi);
+ q[1]=q[2]= 0;
+ QuatToMat3(q, cmat);
+ Mat3MulMat3(tmat, cmat, mat);
+ Mat3MulMat3(cmat, imat, tmat);
+
+ for(a=0; a<seg; a++) {
+ extrudeflag(2, 0);
+ rotateflag(2, v1->co, cmat);
+ }
+ removedoublesflag(4, 0.0001);
+ }
+ else if(type==12) { /* Icosphere */
+ EditVert *eva[12];
+
+ /* 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(vec);
+ eva[a]->f= 1+2;
+ }
+ for(a=0;a<20;a++) {
+ v1= eva[ icoface[a][0] ];
+ v2= eva[ icoface[a][1] ];
+ v3= eva[ icoface[a][2] ];
+ addfacelist(v1, v2, v3, 0, NULL);
+ }
+
+ dia*=200;
+ for(a=1; a<subdiv; a++) subdivideflag(2, dia, 0);
+ /* and now do imat */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 2) {
+ VecAddf(eve->co,eve->co,cent);
+ Mat3MulVecfl(imat,eve->co);
+ }
+ eve= eve->next;
+ }
+ } else if (type==13) { /* 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(v);
+ tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(v);
+ }
+ for (i=0; i<monkeynf; i++) {
+ addfacelist(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);
+ addfacelist(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);
+ }
+
+ MEM_freeN(tv);
+ }
+
+ if(type!=0 && type!=10) righthandfaces(1);
+ countall();
+
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+ allqueue(REDRAWALL, 0);
+ makeDispList(G.obedit);
+
+ if (type==13) notice("Oooh Oooh Oooh");
+}
+
diff --git a/source/blender/src/editmesh_lib.c b/source/blender/src/editmesh_lib.c
new file mode 100644
index 00000000000..a977130c385
--- /dev/null
+++ b/source/blender/src/editmesh_lib.c
@@ -0,0 +1,736 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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 NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+
+#include "editmesh.h"
+
+
+/* ********************* */
+
+int editmesh_nfaces_selected(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ int count= 0;
+
+ for (efa= em->faces.first; efa; efa= efa->next)
+ if (faceselectedAND(efa, SELECT))
+ count++;
+
+ return count;
+}
+
+int editmesh_nvertices_selected(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int count= 0;
+
+ for (eve= em->verts.first; eve; eve= eve->next)
+ if (eve->f & SELECT)
+ count++;
+
+ return count;
+}
+
+/* ***************** */
+
+short extrudeflag(short flag,short type)
+{
+ /* when type=1 old extrusion faces are removed (for spin etc) */
+ /* all verts with (flag & 'flag'): extrude */
+ /* from old verts, 'flag' is cleared, in new ones it is set */
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1, *v2, *v3, *v4, *nextve;
+ EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
+ EditFace *efa, *efa2, *nextvl;
+ short sel=0, deloud= 0, smooth= 0;
+
+ if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
+
+ /* clear vert flag f1, we use this to detext 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->f= 1;
+ eed->v1->f1= 0;
+ eed->v2->f1= 0;
+ }
+ else eed->f= 0;
+
+ eed->f1= 1; /* this indicates it is an 'old' edge (in this routine we make new ones) */
+
+ eed= eed->next;
+ }
+
+ /* we set a flag in all selected faces, and increase the associated edge counters */
+
+ efa= em->faces.first;
+ while(efa) {
+ efa->f= 0;
+
+ if (efa->flag & ME_SMOOTH) {
+ if (faceselectedOR(efa, 1)) smooth= 1;
+ }
+
+ if(faceselectedAND(efa, flag)) {
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ e4= efa->e4;
+
+ if(e1->f < 3) e1->f++;
+ if(e2->f < 3) e2->f++;
+ if(e3->f < 3) e3->f++;
+ if(e4 && e4->f < 3) e4->f++;
+ efa->f= 1;
+ }
+ 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;
+ }
+
+ efa= efa->next;
+ }
+
+ /* set direction of edges */
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f== 0) {
+ if(efa->e1->f==2) {
+ if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
+ else efa->e1->dir= 1;
+ }
+ if(efa->e2->f==2) {
+ if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
+ else efa->e2->dir= 1;
+ }
+ if(efa->e3->f==2) {
+ if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
+ else efa->e3->dir= 1;
+ }
+ if(efa->e4 && efa->e4->f==2) {
+ if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
+ else efa->e4->dir= 1;
+ }
+ }
+ efa= efa->next;
+ }
+
+
+ /* the current state now is:
+ eve->f1==1: loose selected vertex
+
+ eed->f==0 : edge is not selected, no extrude
+ eed->f==1 : edge selected, is not part of a face, extrude
+ eed->f==2 : edge selected, is part of 1 face, extrude
+ eed->f==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, is not part of a selected face
+
+ efa->f==1 : duplicate this face
+ */
+
+ /* copy all selected vertices, */
+ /* write pointer to new vert in old struct at eve->vn */
+ eve= em->verts.last;
+ while(eve) {
+ eve->f&= ~128; /* clear, for later test for loose verts */
+ if(eve->f & flag) {
+ sel= 1;
+ v1= addvertlist(0);
+
+ VECCOPY(v1->co, eve->co);
+ v1->f= eve->f;
+ eve->f-= flag;
+ eve->vn= v1;
+ }
+ else eve->vn= 0;
+ eve= eve->prev;
+ }
+
+ if(sel==0) return 0;
+
+ /* all edges with eed->f==1 or eed->f==2 become faces */
+ /* if deloud==1 then edges with eed->f>2 are removed */
+ eed= em->edges.last;
+ while(eed) {
+ nexted= eed->prev;
+ if( eed->f<3) {
+ eed->v1->f|=128; /* = no loose vert! */
+ eed->v2->f|=128;
+ }
+ if( (eed->f==1 || eed->f==2) ) {
+ if(eed->f1==2) deloud=1;
+
+ if(eed->dir==1) efa2= addfacelist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, NULL);
+ else efa2= addfacelist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, NULL);
+ if (smooth) efa2->flag |= ME_SMOOTH;
+
+ /* 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;
+ }
+ if(deloud) {
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f==3 && eed->f1==1) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+ }
+ /* duplicate faces, if necessart remove old ones */
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f & 1) {
+
+ v1= efa->v1->vn;
+ v2= efa->v2->vn;
+ v3= efa->v3->vn;
+ if(efa->v4) v4= efa->v4->vn; else v4= 0;
+
+ efa2= addfacelist(v1, v2, v3, v4, efa);
+
+ if(deloud) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ if (smooth) efa2->flag |= ME_SMOOTH;
+ }
+ efa= nextvl;
+ }
+ /* for all vertices with eve->vn!=0
+ if eve->f1==1: make edge
+ if flag!=128 : if deloud==1: remove
+ */
+ eve= em->verts.last;
+ while(eve) {
+ nextve= eve->prev;
+ if(eve->vn) {
+ if(eve->f1==1) addedgelist(eve, eve->vn, NULL);
+ else if( (eve->f & 128)==0) {
+ if(deloud) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(eve);
+ eve= NULL;
+ }
+ }
+ }
+ if(eve) eve->f&= ~128;
+
+ eve= nextve;
+ }
+
+ return 1;
+}
+
+void rotateflag(short flag, float *cent, float rotmat[][3])
+{
+ /* all verts with (flag & 'flag') rotate */
+ EditMesh *em = G.editMesh;
+ 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];
+ Mat3MulVecfl(rotmat,eve->co);
+ eve->co[0]+=cent[0];
+ eve->co[1]+=cent[1];
+ eve->co[2]+=cent[2];
+ }
+ eve= eve->next;
+ }
+}
+
+void translateflag(short flag, float *vec)
+{
+ /* all verts with (flag & 'flag') translate */
+ EditMesh *em = G.editMesh;
+ 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;
+ }
+}
+
+
+void delfaceflag(int flag)
+{
+ EditMesh *em = G.editMesh;
+ /* delete all faces with 'flag', including edges and loose vertices */
+ /* in vertices the 'flag' is cleared */
+ EditVert *eve,*nextve;
+ EditEdge *eed, *nexted;
+ EditFace *efa,*nextvl;
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f= 0;
+ eed= eed->next;
+ }
+
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(faceselectedAND(efa, flag)) {
+
+ efa->e1->f= 1;
+ efa->e2->f= 1;
+ efa->e3->f= 1;
+ if(efa->e4) {
+ efa->e4->f= 1;
+ }
+
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ /* all faces with 1, 2 (3) vertices selected: make sure we keep the edges */
+ efa= em->faces.first;
+ while(efa) {
+ efa->e1->f= 0;
+ efa->e2->f= 0;
+ efa->e3->f= 0;
+ if(efa->e4) {
+ efa->e4->f= 0;
+ }
+
+ efa= efa->next;
+ }
+
+ /* test all edges for vertices with 'flag', and clear */
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f==1) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ else if( (eed->v1->f & flag) || (eed->v2->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(eve);
+ }
+ eve= nextve;
+ }
+
+}
+
+/* ********************* */
+
+static int contrpuntnorm(float *n, float *puno) /* dutch: check vertex normal */
+{
+ float inp;
+
+ inp= n[0]*puno[0]+n[1]*puno[1]+n[2]*puno[2];
+
+ /* angles 90 degrees: dont flip */
+ if(inp> -0.000001) return 0;
+
+ return 1;
+}
+
+
+void vertexnormals(int testflip)
+{
+ EditMesh *em = G.editMesh;
+ Mesh *me;
+ EditVert *eve;
+ EditFace *efa;
+ float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp;
+ float *f1, *f2, *f3, *f4, xn, yn, zn;
+ float len;
+
+ if(G.obedit && G.obedit->type==OB_MESH) {
+ me= G.obedit->data;
+ if((me->flag & ME_TWOSIDED)==0) testflip= 0;
+ }
+
+ if(G.totvert==0) return;
+
+ if(G.totface==0) {
+ /* fake vertex normals for 'halo puno'! */
+ eve= em->verts.first;
+ while(eve) {
+ VECCOPY(eve->no, eve->co);
+ Normalise( (float *)eve->no);
+ eve= eve->next;
+ }
+ return;
+ }
+
+ /* clear normals */
+ eve= em->verts.first;
+ while(eve) {
+ eve->no[0]= eve->no[1]= eve->no[2]= 0.0;
+ eve= eve->next;
+ }
+
+ /* calculate cosine angles and add to vertex normal */
+ efa= em->faces.first;
+ while(efa) {
+ VecSubf(n1, efa->v2->co, efa->v1->co);
+ VecSubf(n2, efa->v3->co, efa->v2->co);
+ Normalise(n1);
+ Normalise(n2);
+
+ if(efa->v4==0) {
+ VecSubf(n3, efa->v1->co, efa->v3->co);
+ Normalise(n3);
+
+ co[0]= saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]);
+ co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+
+ }
+ else {
+ VecSubf(n3, efa->v4->co, efa->v3->co);
+ VecSubf(n4, efa->v1->co, efa->v4->co);
+ Normalise(n3);
+ Normalise(n4);
+
+ co[0]= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
+ co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+ co[3]= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
+ }
+
+ temp= efa->v1->no;
+ if(testflip && contrpuntnorm(efa->n, temp) ) co[0]= -co[0];
+ temp[0]+= co[0]*efa->n[0];
+ temp[1]+= co[0]*efa->n[1];
+ temp[2]+= co[0]*efa->n[2];
+
+ temp= efa->v2->no;
+ if(testflip && contrpuntnorm(efa->n, temp) ) co[1]= -co[1];
+ temp[0]+= co[1]*efa->n[0];
+ temp[1]+= co[1]*efa->n[1];
+ temp[2]+= co[1]*efa->n[2];
+
+ temp= efa->v3->no;
+ if(testflip && contrpuntnorm(efa->n, temp) ) co[2]= -co[2];
+ temp[0]+= co[2]*efa->n[0];
+ temp[1]+= co[2]*efa->n[1];
+ temp[2]+= co[2]*efa->n[2];
+
+ if(efa->v4) {
+ temp= efa->v4->no;
+ if(testflip && contrpuntnorm(efa->n, temp) ) co[3]= -co[3];
+ temp[0]+= co[3]*efa->n[0];
+ temp[1]+= co[3]*efa->n[1];
+ temp[2]+= co[3]*efa->n[2];
+ }
+
+ efa= efa->next;
+ }
+
+ /* normalise vertex normals */
+ eve= em->verts.first;
+ while(eve) {
+ len= Normalise(eve->no);
+ if(len==0.0) {
+ VECCOPY(eve->no, eve->co);
+ Normalise( eve->no);
+ }
+ eve= eve->next;
+ }
+
+ /* vertex normal flip-flags for shade (render) */
+ efa= em->faces.first;
+ while(efa) {
+ efa->f=0;
+
+ if(testflip) {
+ f1= efa->v1->no;
+ f2= efa->v2->no;
+ f3= efa->v3->no;
+
+ fac1= efa->n[0]*f1[0] + efa->n[1]*f1[1] + efa->n[2]*f1[2];
+ if(fac1<0.0) {
+ efa->f = ME_FLIPV1;
+ }
+ fac2= efa->n[0]*f2[0] + efa->n[1]*f2[1] + efa->n[2]*f2[2];
+ if(fac2<0.0) {
+ efa->f += ME_FLIPV2;
+ }
+ fac3= efa->n[0]*f3[0] + efa->n[1]*f3[1] + efa->n[2]*f3[2];
+ if(fac3<0.0) {
+ efa->f += ME_FLIPV3;
+ }
+ if(efa->v4) {
+ f4= efa->v4->no;
+ fac4= efa->n[0]*f4[0] + efa->n[1]*f4[1] + efa->n[2]*f4[2];
+ if(fac4<0.0) {
+ efa->f += ME_FLIPV4;
+ }
+ }
+ }
+ /* projection for cubemap! */
+ xn= fabs(efa->n[0]);
+ yn= fabs(efa->n[1]);
+ zn= fabs(efa->n[2]);
+
+ if(zn>xn && zn>yn) efa->f += ME_PROJXY;
+ else if(yn>xn && yn>zn) efa->f += ME_PROJXZ;
+ else efa->f += ME_PROJYZ;
+
+ efa= efa->next;
+ }
+}
+
+void flipface(EditFace *efa)
+{
+ if(efa->v4) {
+ SWAP(EditVert *, efa->v2, efa->v4);
+ SWAP(EditEdge *, efa->e1, efa->e4);
+ SWAP(EditEdge *, efa->e2, efa->e3);
+ SWAP(unsigned int, efa->tf.col[1], efa->tf.col[3]);
+ SWAP(float, efa->tf.uv[1][0], efa->tf.uv[3][0]);
+ SWAP(float, efa->tf.uv[1][1], efa->tf.uv[3][1]);
+ }
+ else {
+ SWAP(EditVert *, efa->v2, efa->v3);
+ SWAP(EditEdge *, efa->e1, efa->e3);
+ SWAP(unsigned int, efa->tf.col[1], efa->tf.col[2]);
+ efa->e2->dir= 1-efa->e2->dir;
+ SWAP(float, efa->tf.uv[1][0], efa->tf.uv[2][0]);
+ SWAP(float, efa->tf.uv[1][1], efa->tf.uv[2][1]);
+ }
+ if(efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
+ else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+}
+
+
+void flip_editnormals(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ efa= em->faces.first;
+ while(efa) {
+ if( faceselectedAND(efa, 1) ) {
+ flipface(efa);
+ }
+ efa= efa->next;
+ }
+}
+
+
+void recalc_editnormals(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
+ else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+ efa= efa->next;
+ }
+}
+
+
+int faceselectedOR(EditFace *efa, int flag)
+{
+
+ if(efa->v1->f & flag) return 1;
+ if(efa->v2->f & flag) return 1;
+ if(efa->v3->f & flag) return 1;
+ if(efa->v4 && (efa->v4->f & 1)) return 1;
+ return 0;
+}
+
+int faceselectedAND(EditFace *efa, int flag)
+{
+ if(efa->v1->f & flag) {
+ if(efa->v2->f & flag) {
+ if(efa->v3->f & flag) {
+ if(efa->v4) {
+ if(efa->v4->f & flag) return 1;
+ }
+ else return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+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;
+}
+
+int exist_face(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
+{
+ EditMesh *em = G.editMesh;
+ 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 1;
+ efa= efa->next;
+ }
+ return 0;
+}
+
+
+float convex(float *v1, float *v2, float *v3, float *v4)
+{
+ float cross[3], test[3];
+ float inpr;
+
+ CalcNormFloat(v1, v2, v3, cross);
+ CalcNormFloat(v1, v3, v4, test);
+
+ inpr= cross[0]*test[0]+cross[1]*test[1]+cross[2]*test[2];
+
+ return inpr;
+}
+
+
diff --git a/source/blender/src/editmesh_loop.c b/source/blender/src/editmesh_loop.c
new file mode 100644
index 00000000000..59572ee2345
--- /dev/null
+++ b/source/blender/src/editmesh_loop.c
@@ -0,0 +1,1843 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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 NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_loop: tools with own drawing subloops, select, knife, subdiv
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_cursors.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "editmesh.h"
+
+/* next 2 includes for knife tool... shouldnt be! (ton) */
+#include "GHOST_C-api.h"
+#include "winlay.h"
+
+
+/* *************** LOOP SELECT ************* */
+
+short edgeFaces(EditEdge *e){
+ EditMesh *em = G.editMesh;
+ 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;
+}
+
+/* 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(EditEdge* e1, EditEdge* e2)
+{
+ EditMesh *em = G.editMesh;
+ 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;
+}
+/* This function selects a vertex loop based on a each succesive edge having a valance of 4
+ and not sharing a face with the previous edge */
+
+void vertex_loop_select()
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1=NULL,*v2=NULL;
+ EditEdge *search=NULL,*startEdge=NULL,*valSearch = NULL,*nearest = NULL,*compEdge;
+ EditEdge *EdgeVal[5] = {NULL,NULL,NULL,NULL,NULL};
+ short numEdges=0,curEdge = 0,looking = 1,edgeValCount = 0,i=0,looped = 0,choosing = 1,event,noloop=0,cancel=0, val;
+ short protect = 0;
+ short mvalo[2] = {0,0}, mval[2];
+
+ undo_push_mesh("Select Vertex Loop");
+ SetBlenderCursor(BC_VLOOPCURSOR);
+ for(search=em->edges.first;search;search=search->next)
+ numEdges++;
+
+ /* start with v1 and go in one direction. */
+ while(choosing){
+ getmouseco_areawin(mval);
+ if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
+
+ mvalo[0] = mval[0];
+ mvalo[1] = mval[1];
+
+ scrarea_do_windraw(curarea);
+ nearest = findnearestedge();
+ if (nearest && edgeFaces(nearest)==2) {
+ for(search = em->edges.first;search;search=search->next)
+ search->f &= ~32;
+
+ compEdge = startEdge = nearest;
+ nearest->f |= 32;
+ curEdge = 0;
+ v1 = startEdge->v1;
+ v2 = startEdge->v2;
+ looking = 1;
+ while(looking){
+ if(protect++ > numEdges) break;
+ if(edgeFaces(compEdge) != 2) break;
+ /*Find Edges that have v1*/
+ edgeValCount = -1;
+ EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
+
+ for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
+ if(valSearch->v1 == v1 || valSearch->v2 == v1){
+ if(valSearch != compEdge){
+ if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
+ if(edgeFaces(valSearch) == 2){
+ edgeValCount++;
+ EdgeVal[edgeValCount] = valSearch;
+ }
+ }
+ }
+ }
+ if(edgeValCount == 3)break;
+ }
+ /* Check that there was a valance of 4*/
+ if(edgeValCount != 2){
+ noloop = 1;
+ looking = 0;
+ break;
+ }
+ else{
+ /* There were 3 edges, so find the one that does not share the previous edge */
+ for(i=0;i<3;i++){
+ if(sharesFace(compEdge,EdgeVal[i]) == 0){
+ /* We went all the way around the loop */
+ if(EdgeVal[i] == nearest){
+ looking = 0;
+ looped = 1;
+ break;
+ }
+ else{
+ /* we are still in the loop, so add the next edge*/
+ curEdge++;
+ EdgeVal[i]->f |= 32;
+ compEdge = EdgeVal[i];
+ if(compEdge->v1 == v1)
+ v1 = compEdge->v2;
+ else
+ v1 = compEdge->v1;
+ }
+ }
+ }
+ }
+ }
+ compEdge = nearest;
+ looking = 1;
+ protect = 0;
+ while(looking/* && !looped*/){
+ if(protect++ > numEdges) break;
+ if(edgeFaces(compEdge) != 2) break;
+ /*Find Edges that have v1*/
+ edgeValCount = -1;
+ EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
+
+ for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
+ if(valSearch->v1 == v2 || valSearch->v2 == v2){
+ if(valSearch != compEdge){
+ if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
+ if(edgeFaces(valSearch) == 2){
+ edgeValCount++;
+ EdgeVal[edgeValCount] = valSearch;
+ }
+ }
+ }
+ }
+ if(edgeValCount == 3)break;
+ }
+ /* Check that there was a valance of 4*/
+ if(edgeValCount != 2){
+ noloop = 1;
+ looking = 0;
+ break;
+ }
+ else{
+ /* There were 3 edges, so find the one that does not share the previous edge */
+ for(i=0;i<3;i++){
+ if(sharesFace(compEdge,EdgeVal[i]) == 0){
+ /* We went all the way around the loop */
+ if(EdgeVal[i] == nearest){
+ looking = 0;
+ looped = 1;
+ break;
+ }
+ else{
+ /* we are still in the loop, so add the next edge*/
+ curEdge++;
+ EdgeVal[i]->f |= 32;
+ compEdge = EdgeVal[i];
+ if(compEdge->v1 == v2)
+ v2 = compEdge->v2;
+ else
+ v2 = compEdge->v1;
+ }
+ }
+ }
+ }
+ }
+ /* set up for opengl drawing in the 3d window */
+ persp(PERSP_VIEW);
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
+ glColor3ub(0, 255, 255);
+ for(search = em->edges.first;search;search= search->next){
+ if(search->f & 32){
+ glBegin(GL_LINES);
+ glVertex3f(search->v1->co[0],search->v1->co[1],search->v1->co[2]);
+ glVertex3f(search->v2->co[0],search->v2->co[1],search->v2->co[2]);
+ glEnd();
+ }
+ }
+
+ glPopMatrix();
+ }
+ }
+
+ screen_swapbuffers();
+
+ while(qtest())
+ {
+ val=0;
+ event= extern_qread(&val);
+ if(val && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE))
+ {
+ if (nearest==NULL)
+ cancel = 1;
+ choosing=0;
+ break;
+ }
+ if(val && (event==ESCKEY || event==RIGHTMOUSE ))
+ {
+ choosing=0;
+ cancel = 1;
+ break;
+ }
+ if(val && (event==BKEY && G.qual==LR_ALTKEY ))
+ {
+
+ SetBlenderCursor(SYSCURSOR);
+ loopoperations(LOOP_SELECT);
+ return;
+ }
+ }
+ }
+ if(!cancel){
+ /* If this is a unmodified select, clear the selection */
+ if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
+ for(search = em->edges.first;search;search= search->next){
+ search->v1->f &= !1;
+ search->v2->f &= !1;
+ }
+ }
+ /* Alt was not pressed, so add to the selection */
+ if(!(G.qual & LR_ALTKEY)){
+ for(search = em->edges.first;search;search= search->next){
+ if(search->f & 32){
+ search->v1->f |= 1;
+ search->v2->f |= 1;
+ }
+ search->f &= ~32;
+ }
+ }
+ /* alt was pressed, so subtract from the selection */
+ else
+ {
+ for(search = em->edges.first;search;search= search->next){
+ if(search->f & 32){
+ search->v1->f &= !1;
+ search->v2->f &= !1;
+ }
+ search->f &= ~32;
+ }
+ }
+ }
+ else
+ undo_pop_mesh(1);
+ addqueue(curarea->win, REDRAW, 1);
+ SetBlenderCursor(SYSCURSOR);
+ return;
+}
+
+/* *********** END LOOP SELECT ********** */
+
+
+
+/* ***************** 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 {
+ short x;
+ short y;
+} CutCurve;
+
+CutCurve *get_mouse_trail(int *len, char mode){
+
+ CutCurve *curve,*temp;
+ short event, val, ldown=0, restart=0, rubberband=0;
+ short mval[2], lockaxis=0, lockx=0, locky=0, lastx=0, lasty=0;
+ int i=0, j, blocks=1, lasti=0;
+
+ *len=0;
+ curve=(CutCurve *)MEM_callocN(1024*sizeof(CutCurve), "MouseTrail");
+
+ if (!curve) {
+ printf("failed to allocate memory in get_mouse_trail()\n");
+ return(NULL);
+ }
+ mywinset(curarea->win);
+ glDrawBuffer(GL_FRONT);
+
+ headerprint("LMB to draw, Enter to finish, ESC to abort.");
+
+ persp(PERSP_WIN);
+
+ glColor3ub(200, 200, 0);
+
+ while(TRUE) {
+
+ event=extern_qread(&val); /* Enter or RMB indicates finish */
+ if(val) {
+ if(event==RETKEY || event==PADENTER) break;
+ }
+
+ if( event==ESCKEY || event==RIGHTMOUSE ) {
+ if (curve) MEM_freeN(curve);
+ *len=0;
+ glFlush();
+ glDrawBuffer(GL_BACK);
+ return(NULL);
+ break;
+ }
+
+ if (rubberband) { /* rubberband mode, undraw last rubberband */
+ glLineWidth(2.0);
+ sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
+ glLineWidth(1.0);
+ glFlush();
+ rubberband=0;
+ }
+
+ getmouseco_areawin(mval);
+
+ if (lockaxis==1) mval[1]=locky;
+ if (lockaxis==2) mval[0]=lockx;
+
+ if ( ((i==0) || (mval[0]!=curve[i-1].x) || (mval[1]!=curve[i-1].y))
+ && (get_mbut() & L_MOUSE) ){ /* record changes only, if LMB down */
+
+ lastx=curve[i].x=mval[0];
+ lasty=curve[i].y=mval[1];
+
+ lockaxis=0;
+
+ i++;
+
+ ldown=1;
+ if (restart) {
+ for(j=1;j<i;j++) sdrawXORline(curve[j-1].x, curve[j-1].y, curve[j].x, curve[j].y);
+ if (rubberband) sdrawXORline(curve[j].x, curve[j].y, mval[0], mval[1]);
+ glFlush();
+ rubberband=0;
+ lasti=i=0;
+ restart=0;
+ ldown=0;
+ }
+ }
+
+ if ((event==MIDDLEMOUSE)&&(get_mbut()&M_MOUSE)&&(i)){/*MMB Down*/
+ /*determine which axis to lock to, or clear if locked */
+ if (lockaxis) lockaxis=0;
+ else if (abs(curve[i-1].x-mval[0]) > abs(curve[i-1].y-mval[1])) lockaxis=1;
+ else lockaxis=2;
+
+ if (lockaxis) {
+ lockx=lastx;
+ locky=lasty;
+ }
+ }
+
+ if ((i>1)&&(i!=lasti)) { /*Draw recorded part of curve */
+ sdrawline(curve[i-2].x, curve[i-2].y, curve[i-1].x, curve[i-1].y);
+ glFlush();
+ }
+
+ if ((i==lasti)&&(i>0)) { /*Draw rubberband */
+ glLineWidth(2.0);
+ sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
+ glLineWidth(1.0);
+ glFlush();
+ rubberband=1;
+ }
+ lasti=i;
+
+ if (i>=blocks*1024) { /* reallocate data if out of room */
+ temp=curve;
+ curve=(CutCurve *)MEM_callocN((blocks+1)*1024*sizeof(CutCurve), "MouseTrail");
+ if (!curve) {
+ printf("failed to re-allocate memory in get_mouse_trail()\n");
+ return(NULL);
+ }
+ memcpy(curve, temp, blocks*1024*sizeof(CutCurve));
+ blocks++;
+ MEM_freeN(temp);
+ }
+ }
+
+ glFlush();
+ glDrawBuffer(GL_BACK);
+ persp(PERSP_VIEW);
+
+ *len=i;
+
+ return(curve);
+}
+
+
+
+
+/* ******************************************************************** */
+/* 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).
+*/
+
+/* prototype */
+short seg_intersect(struct EditEdge * e, CutCurve *c, int len);
+
+void KnifeSubdivide(char mode){
+ EditMesh *em = G.editMesh;
+ int oldcursor, len=0;
+ short isect=0;
+ CutCurve *curve;
+ EditEdge *eed;
+ Window *win;
+
+ if (G.obedit==0) return;
+
+ if (editmesh_nvertices_selected() < 2) {
+ error("No edges are selected to operate on");
+ return;
+ }
+
+ if (mode==KNIFE_PROMPT) {
+ short val= pupmenu("Cut Type %t|Exact Line%x1|Midpoints%x2");
+ if(val<1) return;
+ mode= val; // warning, mode is char, pupmenu returns -1 with ESC
+ }
+
+ undo_push_mesh("Knife");
+
+ calc_meshverts_ext(); /*Update screen coords for current window */
+
+ /* Set a knife cursor here */
+ oldcursor=get_cursor();
+
+ win=winlay_get_active_window();
+
+ SetBlenderCursor(BC_KNIFECURSOR);
+
+ curve=get_mouse_trail(&len, TRAIL_MIXED);
+
+ if (curve && len && mode){
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->v1->f&1)&&(eed->v2->f&1)){
+ isect=seg_intersect(eed, curve, len);
+ if (isect) eed->f=1;
+ else eed->f=0;
+ eed->f1=isect;
+ //printf("isect=%i\n", isect);
+ }
+ else {
+ eed->f=0;
+ eed->f1=0;
+ }
+ eed= eed->next;
+ }
+
+ if (mode==1) subdivideflag(1, 0, B_KNIFE|B_PERCENTSUBD);
+ else if (mode==2) subdivideflag(1, 0, B_KNIFE);
+
+ eed=em->edges.first;
+ while(eed){
+ eed->f=0;
+ eed->f1=0;
+ eed=eed->next;
+ }
+ }
+ /* Return to old cursor and flags...*/
+
+ addqueue(curarea->win, REDRAW, 0);
+ window_set_cursor(win, oldcursor);
+ if (curve) MEM_freeN(curve);
+}
+
+/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
+
+short seg_intersect(EditEdge *e, CutCurve *c, int len){
+#define MAXSLOPE 100000
+ short isect=0;
+ 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[2], co[4];
+ int i;
+
+ /* Get screen coords of verts (v->xs and v->ys clip if off screen */
+ VECCOPY(co, e->v1->co);
+ co[3]= 1.0;
+ Mat4MulVec4fl(G.obedit->obmat, co);
+ project_float(co, scr);
+ x21=scr[0];
+ y21=scr[1];
+
+ VECCOPY(co, e->v2->co);
+ co[3]= 1.0;
+ Mat4MulVec4fl(G.obedit->obmat, co);
+ project_float(co, scr);
+ 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;
+ }
+ 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)){
+ 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(isect);
+}
+
+/* ******************** LOOP ******************************************* */
+
+/* BTW: this loop function is totally out of control!
+ can be half the code, and using structured functions (ton) */
+
+/*
+functionality: various loop functions
+parameters: mode tells the function what it should do with the loop:
+ LOOP_SELECT = select
+ LOOP_CUT = cut in half
+*/
+
+/* does the same as findnearestedge but both vertices of the edge should be on screen*/
+static EditEdge *findnearestvisibleedge()
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *closest, *eed;
+ EditVert *eve;
+ short found=0, mval[2];
+ float distance[2], v1[2], v2[2], mval2[2];
+
+ if(em->edges.first==0) return NULL;
+ else eed=em->edges.first;
+
+ /* reset flags */
+ for(eve=em->verts.first; eve; eve=eve->next){
+ eve->f &= ~2;
+ }
+ calc_meshverts_ext_f2(); /*sets (eve->f & 2) for vertices that aren't visible*/
+
+ closest=NULL;
+ getmouseco_areawin(mval);
+
+ mval2[0] = (float)mval[0]; /* cast to float because of the pdist function only taking floats...*/
+ mval2[1] = (float)mval[1];
+
+ eed=em->edges.first;
+ while(eed) { /* compare the distance to the rest of the edges and find the closest one*/
+ if( !((eed->v1->f | eed->v2->f) & 2) && (eed->v1->h==0 && eed->v2->h==0) ){ /* only return edges with both vertices on screen */
+ v1[0] = eed->v1->xs;
+ v1[1] = eed->v1->ys;
+ v2[0] = eed->v2->xs;
+ v2[1] = eed->v2->ys;
+
+ distance[1] = PdistVL2Dfl(mval2, v1, v2);
+
+ if(distance[1]<50){ /* TODO: make this maximum selecting distance selectable (the same with vertice select?) */
+ if(found) { /*do we have to compare it to other distances? */
+ if (distance[1]<distance[0]){
+ distance[0]=distance[1];
+ closest=eed; /*save the current closest edge*/
+ }
+ } else {
+ distance[0]=distance[1];
+ closest=eed;
+ found=1;
+ }
+ }
+ }
+ eed= eed->next;
+ }
+
+ /* reset flags */
+ for(eve=em->verts.first; eve; eve=eve->next){
+ eve->f &= ~2;
+ }
+
+ if(found) return closest;
+ else return 0;
+}
+
+
+void loopoperations(char mode)
+{
+ EditMesh *em = G.editMesh;
+ EditVert* look = NULL;
+
+ EditEdge *start, *eed, *opposite,*currente, *oldstart;
+ EditEdge **tagged = NULL,**taggedsrch = NULL,*close;
+
+ EditFace *efa,**percentfacesloop = NULL, *currentvl, *formervl;
+
+ short lastface=0, foundedge=0, c=0, tri=0, side=1, totface=0, searching=1, event=0, noface=1;
+ short skip,nextpos,percentfaces;
+
+ int i=0,ect=0,j=0,k=0,cut,smooth,timesthrough=0,inset = 0;
+
+ float percentcut, outcut;
+
+ char mesg[100];
+
+ if ((G.obedit==0) || (em->faces.first==0)) return;
+
+ if(mode==LOOP_CUT)undo_push_mesh("Face Loop Subdivide");
+ else if(mode==LOOP_SELECT)undo_push_mesh("Select Face Loop");
+
+ SetBlenderCursor(BC_VLOOPCURSOR);
+
+ start=NULL;
+ oldstart=NULL;
+
+ while(searching){
+
+ /* reset variables */
+ start=eed=opposite=currente=0;
+ efa=currentvl=formervl=0;
+ side=noface=1;
+ lastface=foundedge=c=tri=totface=0;
+
+ start=findnearestvisibleedge();
+
+ /* If the edge doesn't belong to a face, it's not a valid starting edge */
+ /* and only accept starting edge if it is part of at least one visible face */
+ if(start){
+ start->f |= 16;
+ efa=em->faces.first;
+ while(efa){
+ if(efa->e1->f & 16){
+ /* since this edge is on the face, check if the face has any hidden verts */
+ if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
+ noface=0;
+ efa->e1->f &= ~16;
+ }
+ }
+ else if(efa->e2->f & 16){
+ if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
+ noface=0;
+ efa->e2->f &= ~16;
+ }
+ }
+ else if(efa->e3->f & 16){
+ if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
+ noface=0;
+ efa->e3->f &= ~16;
+ }
+ }
+ else if(efa->e4 && (efa->e4->f & 16)){
+ if( !efa->v1->h && !efa->v2->h && !efa->v3->h && (efa->v4 && !efa->v4->h) ){
+ noface=0;
+ efa->e4->f &= ~16;
+ }
+ }
+
+ efa=efa->next;
+ }
+ }
+
+ /* Did we find anything that is selectable? */
+ if(start && !noface && (oldstart==NULL || start!=oldstart)){
+
+ /* If we stay in the neighbourhood of this edge, we don't have to recalculate the loop everytime*/
+ oldstart=start;
+
+ /* Clear flags */
+ for(eed=em->edges.first; eed; eed=eed->next){
+ eed->f &= ~(2|4|8|32|64);
+ eed->v1->f &= ~(2|8|16);
+ eed->v2->f &= ~(2|8|16);
+ }
+
+ for(efa= em->faces.first; efa; efa=efa->next){
+ efa->f &= ~(4|8);
+ totface++;
+ }
+
+ /* Tag the starting edge */
+ start->f |= (2|4|8|64);
+ start->v1->f |= 2;
+ start->v2->f |= 2;
+
+ currente=start;
+
+ /*-----Limit the Search----- */
+ while(!lastface && c<totface+1){
+
+ /*----------Get Loop------------------------*/
+ tri=foundedge=lastface=0;
+ efa= em->faces.first;
+ while(efa && !foundedge && !tri){
+
+ if(!(efa->v4)){ /* Exception for triangular faces */
+
+ if((efa->e1->f | efa->e2->f | efa->e3->f) & 2){
+ if(!(efa->f & 4)){
+ tri=1;
+ currentvl=efa;
+ if(side==1) efa->f |= 4;
+ }
+ }
+ }
+ else{
+
+ if((efa->e1->f | efa->e2->f | efa->e3->f | efa->e4->f) & 2){
+
+ if(c==0){ /* just pick a face, doesn't matter wich side of the edge we go to */
+ if(!(efa->f & 4)){
+
+ if(!(efa->e1->v1->f & 2) && !(efa->e1->v2->f & 2)){
+ if(efa->e1->v1->h==0 && efa->e1->v2->h==0){
+ opposite=efa->e1;
+ foundedge=1;
+ }
+ }
+ else if(!(efa->e2->v1->f & 2) && !(efa->e2->v2->f & 2)){
+ if(efa->e2->v1->h==0 && efa->e2->v2->h==0){
+ opposite=efa->e2;
+ foundedge=1;
+ }
+ }
+ else if(!(efa->e3->v1->f & 2) && !(efa->e3->v2->f & 2)){
+ if(efa->e3->v1->h==0 && efa->e3->v2->h==0){
+ opposite=efa->e3;
+ foundedge=1;
+ }
+ }
+ else if(!(efa->e4->v1->f & 2) && !(efa->e4->v2->f & 2)){
+ if(efa->e4->v1->h==0 && efa->e4->v2->h==0){
+ opposite=efa->e4;
+ foundedge=1;
+ }
+ }
+
+ if(foundedge){
+ currentvl=efa;
+ formervl=efa;
+
+ /* mark this side of the edge so we know in which direction we went */
+ if(side==1) efa->f |= 4;
+ }
+ }
+ }
+ else {
+ if(efa!=formervl){ /* prevent going backwards in the loop */
+
+ if(!(efa->e1->v1->f & 2) && !(efa->e1->v2->f & 2)){
+ if(efa->e1->v1->h==0 && efa->e1->v2->h==0){
+ opposite=efa->e1;
+ foundedge=1;
+ }
+ }
+ else if(!(efa->e2->v1->f & 2) && !(efa->e2->v2->f & 2)){
+ if(efa->e2->v1->h==0 && efa->e2->v2->h==0){
+ opposite=efa->e2;
+ foundedge=1;
+ }
+ }
+ else if(!(efa->e3->v1->f & 2) && !(efa->e3->v2->f & 2)){
+ if(efa->e3->v1->h==0 && efa->e3->v2->h==0){
+ opposite=efa->e3;
+ foundedge=1;
+ }
+ }
+ else if(!(efa->e4->v1->f & 2) && !(efa->e4->v2->f & 2)){
+ if(efa->e4->v1->h==0 && efa->e4->v2->h==0){
+ opposite=efa->e4;
+ foundedge=1;
+ }
+ }
+
+ currentvl=efa;
+ }
+ }
+ }
+ }
+ efa=efa->next;
+ }
+ /*----------END Get Loop------------------------*/
+
+
+ /*----------Decisions-----------------------------*/
+ if(foundedge){
+ /* mark the edge and face as done */
+ currente->f |= 8;
+ currentvl->f |= 8;
+
+ if(opposite->f & 4) lastface=1; /* found the starting edge! close loop */
+ else{
+ /* un-set the testflags */
+ currente->f &= ~2;
+ currente->v1->f &= ~2;
+ currente->v2->f &= ~2;
+
+ /* set the opposite edge to be the current edge */
+ currente=opposite;
+
+ /* set the current face to be the FORMER face (to prevent going backwards in the loop) */
+ formervl=currentvl;
+
+ /* set the testflags */
+ currente->f |= 2;
+ currente->v1->f |= 2;
+ currente->v2->f |= 2;
+ }
+ c++;
+ }
+ else{
+ /* un-set the testflags */
+ currente->f &= ~2;
+ currente->v1->f &= ~2;
+ currente->v2->f &= ~2;
+
+ /* mark the edge and face as done */
+ currente->f |= 8;
+ currentvl->f |= 8;
+
+
+
+ /* is the the first time we've ran out of possible faces?
+ * try to start from the beginning but in the opposite direction go as far as possible
+ */
+ if(side==1){
+ if(tri)tri=0;
+ currente=start;
+ currente->f |= 2;
+ currente->v1->f |= 2;
+ currente->v2->f |= 2;
+ side++;
+ c=0;
+ }
+ else lastface=1;
+ }
+ /*----------END Decisions-----------------------------*/
+
+ }
+ /*-----END Limit the Search----- */
+
+
+ /*------------- Preview lines--------------- */
+
+ /* uses callback mechanism to draw it all in current area */
+ scrarea_do_windraw(curarea);
+
+ /* set window matrix to perspective, default an area returns with buttons transform */
+ persp(PERSP_VIEW);
+ /* make a copy, for safety */
+ glPushMatrix();
+ /* multiply with the object transformation */
+ mymultmatrix(G.obedit->obmat);
+
+ glColor3ub(255, 255, 0);
+
+ if(mode==LOOP_SELECT){
+ efa= em->faces.first;
+ while(efa){
+ if(efa->f & 8){
+
+ if(!(efa->e1->f & 8)){
+ glBegin(GL_LINES);
+ glVertex3fv(efa->e1->v1->co);
+ glVertex3fv(efa->e1->v2->co);
+ glEnd();
+ }
+
+ if(!(efa->e2->f & 8)){
+ glBegin(GL_LINES);
+ glVertex3fv(efa->e2->v1->co);
+ glVertex3fv(efa->e2->v2->co);
+ glEnd();
+ }
+
+ if(!(efa->e3->f & 8)){
+ glBegin(GL_LINES);
+ glVertex3fv(efa->e3->v1->co);
+ glVertex3fv(efa->e3->v2->co);
+ glEnd();
+ }
+
+ if(efa->e4){
+ if(!(efa->e4->f & 8)){
+ glBegin(GL_LINES);
+ glVertex3fv(efa->e4->v1->co);
+ glVertex3fv(efa->e4->v2->co);
+ glEnd();
+ }
+ }
+ }
+ efa=efa->next;
+ }
+ }
+
+ if(mode==LOOP_CUT){
+ efa= em->faces.first;
+ while(efa){
+ if(efa->f & 8){
+ float cen[2][3];
+ int a=0;
+
+ efa->v1->f &= ~8;
+ efa->v2->f &= ~8;
+ efa->v3->f &= ~8;
+ if(efa->v4)efa->v4->f &= ~8;
+
+ if(efa->e1->f & 8){
+ cen[a][0]= (efa->e1->v1->co[0] + efa->e1->v2->co[0])/2.0;
+ cen[a][1]= (efa->e1->v1->co[1] + efa->e1->v2->co[1])/2.0;
+ cen[a][2]= (efa->e1->v1->co[2] + efa->e1->v2->co[2])/2.0;
+
+ efa->e1->v1->f |= 8;
+ efa->e1->v2->f |= 8;
+
+ a++;
+ }
+ if((efa->e2->f & 8) && a!=2){
+ cen[a][0]= (efa->e2->v1->co[0] + efa->e2->v2->co[0])/2.0;
+ cen[a][1]= (efa->e2->v1->co[1] + efa->e2->v2->co[1])/2.0;
+ cen[a][2]= (efa->e2->v1->co[2] + efa->e2->v2->co[2])/2.0;
+
+ efa->e2->v1->f |= 8;
+ efa->e2->v2->f |= 8;
+
+ a++;
+ }
+ if((efa->e3->f & 8) && a!=2){
+ cen[a][0]= (efa->e3->v1->co[0] + efa->e3->v2->co[0])/2.0;
+ cen[a][1]= (efa->e3->v1->co[1] + efa->e3->v2->co[1])/2.0;
+ cen[a][2]= (efa->e3->v1->co[2] + efa->e3->v2->co[2])/2.0;
+
+ efa->e3->v1->f |= 8;
+ efa->e3->v2->f |= 8;
+
+ a++;
+ }
+
+ if(efa->e4){
+ if((efa->e4->f & 8) && a!=2){
+ cen[a][0]= (efa->e4->v1->co[0] + efa->e4->v2->co[0])/2.0;
+ cen[a][1]= (efa->e4->v1->co[1] + efa->e4->v2->co[1])/2.0;
+ cen[a][2]= (efa->e4->v1->co[2] + efa->e4->v2->co[2])/2.0;
+
+ efa->e4->v1->f |= 8;
+ efa->e4->v2->f |= 8;
+
+ a++;
+ }
+ }
+ else{ /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
+ if(!(efa->v1->f & 8) && efa->v1->h==0){
+ cen[a][0]= efa->v1->co[0];
+ cen[a][1]= efa->v1->co[1];
+ cen[a][2]= efa->v1->co[2];
+ a++;
+ }
+ else if(!(efa->v2->f & 8) && efa->v2->h==0){
+ cen[a][0]= efa->v2->co[0];
+ cen[a][1]= efa->v2->co[1];
+ cen[a][2]= efa->v2->co[2];
+ a++;
+ }
+ else if(!(efa->v3->f & 8) && efa->v3->h==0){
+ cen[a][0]= efa->v3->co[0];
+ cen[a][1]= efa->v3->co[1];
+ cen[a][2]= efa->v3->co[2];
+ a++;
+ }
+ }
+
+ if(a==2){
+ glBegin(GL_LINES);
+
+ glVertex3fv(cen[0]);
+ glVertex3fv(cen[1]);
+
+ glEnd();
+ }
+ }
+ efa=efa->next;
+ }
+
+ eed=em->edges.first;
+ while(eed){
+ if(eed->f & 64){
+ glBegin(GL_LINES);
+ glColor3ub(200, 255, 200);
+ glVertex3fv(eed->v1->co);
+ glVertex3fv(eed->v2->co);
+ glEnd();
+ eed=0;
+ }else{
+ eed = eed->next;
+ }
+ }
+ }
+
+ /* restore matrix transform */
+ glPopMatrix();
+
+ headerprint("LMB to confirm, RMB to cancel");
+
+ /* this also verifies other area/windows for clean swap */
+ screen_swapbuffers();
+
+ /*--------- END Preview Lines------------*/
+
+ }/*if(start!=NULL){ */
+
+ while(qtest()) {
+ unsigned 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 && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event == MIDDLEMOUSE)){
+ searching=0;
+ }
+ }
+
+ }/*while(event!=ESCKEY && event!=RIGHTMOUSE && event!=LEFTMOUSE && event!=RETKEY){*/
+
+ /*----------Select Loop------------*/
+ if(mode==LOOP_SELECT && start!=NULL && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE || event == BKEY)){
+
+ /* If this is a unmodified select, clear the selection */
+ if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
+ for(efa= em->faces.first;efa;efa=efa->next){
+ efa->v1->f &= !1;
+ efa->v2->f &= !1;
+ efa->v3->f &= !1;
+ if(efa->v4)efa->v4->f &= !1;
+ }
+ }
+ /* Alt was not pressed, so add to the selection */
+ if(!(G.qual & LR_ALTKEY)){
+ for(efa= em->faces.first;efa;efa=efa->next){
+ if(efa->f & 8){
+ efa->v1->f |= 1;
+ efa->v2->f |= 1;
+ efa->v3->f |= 1;
+ if(efa->v4)efa->v4->f |= 1;
+ }
+ }
+ }
+ /* alt was pressed, so subtract from the selection */
+ else
+ {
+ for(efa= em->faces.first;efa;efa=efa->next){
+ if(efa->f & 8){
+ efa->v1->f &= !1;
+ efa->v2->f &= !1;
+ efa->v3->f &= !1;
+ if(efa->v4)efa->v4->f &= !1;
+ }
+ }
+ }
+
+ }
+ /*----------END Select Loop------------*/
+
+ /*----------Cut Loop---------------*/
+ if(mode==LOOP_CUT && start!=NULL && (event==LEFTMOUSE || event==RETKEY)){
+
+ /* count the number of edges in the loop */
+ for(eed=em->edges.first; eed; eed = eed->next){
+ if(eed->f & 8)
+ ect++;
+ }
+
+ tagged = MEM_mallocN(ect*sizeof(EditEdge*), "tagged");
+ taggedsrch = MEM_mallocN(ect*sizeof(EditEdge*), "taggedsrch");
+ for(i=0;i<ect;i++)
+ {
+ tagged[i] = NULL;
+ taggedsrch[i] = NULL;
+ }
+ ect = 0;
+ for(eed=em->edges.first; eed; eed = eed->next){
+ if(eed->f & 8)
+ {
+ if(eed->h==0){
+ eed->v1->f |= 1;
+ eed->v2->f |= 1;
+ tagged[ect] = eed;
+ eed->f &= ~(32);
+ ect++;
+ }
+ }
+ }
+ taggedsrch[0] = tagged[0];
+
+ while(timesthrough < 2)
+ {
+ i=0;
+ while(i < ect){/*Look at the members of the search array to line up cuts*/
+ if(taggedsrch[i]==NULL)break;
+ for(j=0;j<ect;j++){ /*Look through the list of tagged verts for connected edges*/
+ int addededge = 0;
+ if(taggedsrch[i]->f & 32) /*If this edgee is marked as flipped, use vert 2*/
+ look = taggedsrch[i]->v2;
+ else /*else use vert 1*/
+ look = taggedsrch[i]->v1;
+
+ if(taggedsrch[i] == tagged[j])
+ continue; /*If we are looking at the same edge, skip it*/
+
+ skip = 0;
+ for(k=0;k<ect;k++) {
+ if(taggedsrch[k] == NULL) /*go to empty part of search list without finding*/
+ break;
+ if(tagged[j] == taggedsrch[k]){ /*We found a match already in the list*/
+ skip = 1;
+ break;
+ }
+ }
+ if(skip)
+ continue;
+ nextpos = 0;
+ if(findedgelist(look,tagged[j]->v2)){
+ while(nextpos < ect){ /*Find the first open spot in the search array*/
+ if(taggedsrch[nextpos] == NULL){
+ taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
+ taggedsrch[nextpos]->f |= 32;
+ addededge = 1;
+ break;
+ }
+ else
+ nextpos++;
+ }
+ } /* End else if connected to vert 2*/
+ else if(findedgelist(look,tagged[j]->v1)){ /*If our vert is connected to vert 1 */
+ while(nextpos < ect){ /*Find the first open spot in the search array */
+ if(taggedsrch[nextpos] == NULL){
+ taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
+ addededge = 1;
+ break;
+ }
+ else
+ nextpos++;
+ }
+ }
+
+ if(addededge)
+ {
+ break;
+ }
+ }/* End Outer For (j)*/
+ i++;
+ } /* End while(j<ect)*/
+ timesthrough++;
+ } /*end while timesthrough */
+ percentcut = 0.50;
+ searching = 1;
+ cut = 1;
+ smooth = 0;
+ close = NULL;
+
+
+ /* Count the Number of Faces in the selected loop*/
+ percentfaces = 0;
+ for(efa= em->faces.first; efa ;efa=efa->next){
+ if(efa->f & 8)
+ {
+ percentfaces++;
+ }
+ }
+
+ /* create a dynamic array for those face pointers */
+ percentfacesloop = MEM_mallocN(percentfaces*sizeof(EditFace*), "percentage");
+
+ /* put those faces in the array */
+ i=0;
+ for(efa= em->faces.first; efa ;efa=efa->next){
+ if(efa->f & 8)
+ {
+ percentfacesloop[i] = efa;
+ i++;
+ }
+ }
+
+ while(searching){
+
+ /* For the % calculation */
+ short mval[2];
+ float labda, rc[2], len, slen=0.0;
+ float v1[2], v2[2], v3[2];
+
+ /*------------- Percent Cut Preview Lines--------------- */
+ scrarea_do_windraw(curarea);
+ persp(PERSP_VIEW);
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
+ glColor3ub(0, 255, 255);
+
+ /*Put the preview lines where they should be for the percentage selected.*/
+
+ for(i=0;i<percentfaces;i++){
+ efa = percentfacesloop[i];
+ for(eed = em->edges.first; eed; eed=eed->next){
+ if(eed->f & 64){ /* color the starting edge */
+ glBegin(GL_LINES);
+
+ glColor3ub(200, 255, 200);
+ glVertex3fv(eed->v1->co);
+ glVertex3fv(eed->v2->co);
+
+ glEnd();
+
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ glColor3ub(255,0,255);
+
+ if(eed->f & 32)
+ glVertex3fv(eed->v2->co);
+ else
+ glVertex3fv(eed->v1->co);
+ glEnd();
+
+
+ /*Get Starting Edge Length*/
+ slen = sqrt((eed->v1->co[0]-eed->v2->co[0])*(eed->v1->co[0]-eed->v2->co[0])+
+ (eed->v1->co[1]-eed->v2->co[1])*(eed->v1->co[1]-eed->v2->co[1])+
+ (eed->v1->co[2]-eed->v2->co[2])*(eed->v1->co[2]-eed->v2->co[2]));
+ }
+ }
+
+ if(!inset){
+ glColor3ub(0,255,255);
+ if(efa->f & 8)
+ {
+ float cen[2][3];
+ int a=0;
+
+ efa->v1->f &= ~8;
+ efa->v2->f &= ~8;
+ efa->v3->f &= ~8;
+ if(efa->v4)efa->v4->f &= ~8;
+
+ if(efa->e1->f & 8){
+ float pct;
+ if(efa->e1->f & 32)
+ pct = 1-percentcut;
+ else
+ pct = percentcut;
+ cen[a][0]= efa->e1->v1->co[0] - ((efa->e1->v1->co[0] - efa->e1->v2->co[0]) * (pct));
+ cen[a][1]= efa->e1->v1->co[1] - ((efa->e1->v1->co[1] - efa->e1->v2->co[1]) * (pct));
+ cen[a][2]= efa->e1->v1->co[2] - ((efa->e1->v1->co[2] - efa->e1->v2->co[2]) * (pct));
+ efa->e1->v1->f |= 8;
+ efa->e1->v2->f |= 8;
+ a++;
+ }
+ if((efa->e2->f & 8) && a!=2)
+ {
+ float pct;
+ if(efa->e2->f & 32)
+ pct = 1-percentcut;
+ else
+ pct = percentcut;
+ cen[a][0]= efa->e2->v1->co[0] - ((efa->e2->v1->co[0] - efa->e2->v2->co[0]) * (pct));
+ cen[a][1]= efa->e2->v1->co[1] - ((efa->e2->v1->co[1] - efa->e2->v2->co[1]) * (pct));
+ cen[a][2]= efa->e2->v1->co[2] - ((efa->e2->v1->co[2] - efa->e2->v2->co[2]) * (pct));
+
+ efa->e2->v1->f |= 8;
+ efa->e2->v2->f |= 8;
+
+ a++;
+ }
+ if((efa->e3->f & 8) && a!=2){
+ float pct;
+ if(efa->e3->f & 32)
+ pct = 1-percentcut;
+ else
+ pct = percentcut;
+ cen[a][0]= efa->e3->v1->co[0] - ((efa->e3->v1->co[0] - efa->e3->v2->co[0]) * (pct));
+ cen[a][1]= efa->e3->v1->co[1] - ((efa->e3->v1->co[1] - efa->e3->v2->co[1]) * (pct));
+ cen[a][2]= efa->e3->v1->co[2] - ((efa->e3->v1->co[2] - efa->e3->v2->co[2]) * (pct));
+
+ efa->e3->v1->f |= 8;
+ efa->e3->v2->f |= 8;
+
+ a++;
+ }
+
+ if(efa->e4){
+ if((efa->e4->f & 8) && a!=2){
+ float pct;
+ if(efa->e4->f & 32)
+ pct = 1-percentcut;
+ else
+ pct = percentcut;
+ cen[a][0]= efa->e4->v1->co[0] - ((efa->e4->v1->co[0] - efa->e4->v2->co[0]) * (pct));
+ cen[a][1]= efa->e4->v1->co[1] - ((efa->e4->v1->co[1] - efa->e4->v2->co[1]) * (pct));
+ cen[a][2]= efa->e4->v1->co[2] - ((efa->e4->v1->co[2] - efa->e4->v2->co[2]) * (pct));
+
+ efa->e4->v1->f |= 8;
+ efa->e4->v2->f |= 8;
+
+ a++;
+ }
+ }
+ else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
+ if(!(efa->v1->f & 8) && efa->v1->h==0){
+ cen[a][0]= efa->v1->co[0];
+ cen[a][1]= efa->v1->co[1];
+ cen[a][2]= efa->v1->co[2];
+ a++;
+ }
+ else if(!(efa->v2->f & 8) && efa->v2->h==0){
+ cen[a][0]= efa->v2->co[0];
+ cen[a][1]= efa->v2->co[1];
+ cen[a][2]= efa->v2->co[2];
+ a++;
+ }
+ else if(!(efa->v3->f & 8) && efa->v3->h==0){
+ cen[a][0]= efa->v3->co[0];
+ cen[a][1]= efa->v3->co[1];
+ cen[a][2]= efa->v3->co[2];
+ a++;
+ }
+ }
+
+ if(a==2){
+ glBegin(GL_LINES);
+
+ glVertex3fv(cen[0]);
+ glVertex3fv(cen[1]);
+
+ glEnd();
+ }
+ }
+ }/* end preview line drawing */
+ else{
+ glColor3ub(0,128,255);
+ if(efa->f & 8)
+ {
+ float cen[2][3];
+ int a=0;
+
+ efa->v1->f &= ~8;
+ efa->v2->f &= ~8;
+ efa->v3->f &= ~8;
+ if(efa->v4)efa->v4->f &= ~8;
+
+ if(efa->e1->f & 8){
+ float nlen,npct;
+
+ nlen = sqrt((efa->e1->v1->co[0] - efa->e1->v2->co[0])*(efa->e1->v1->co[0] - efa->e1->v2->co[0])+
+ (efa->e1->v1->co[1] - efa->e1->v2->co[1])*(efa->e1->v1->co[1] - efa->e1->v2->co[1])+
+ (efa->e1->v1->co[2] - efa->e1->v2->co[2])*(efa->e1->v1->co[2] - efa->e1->v2->co[2]));
+ npct = (percentcut*slen)/nlen;
+ if(npct >= 1) npct = 1;
+ if(efa->e1->f & 32) npct = 1-npct;
+
+ cen[a][0]= efa->e1->v1->co[0] - ((efa->e1->v1->co[0] - efa->e1->v2->co[0]) * (npct));
+ cen[a][1]= efa->e1->v1->co[1] - ((efa->e1->v1->co[1] - efa->e1->v2->co[1]) * (npct));
+ cen[a][2]= efa->e1->v1->co[2] - ((efa->e1->v1->co[2] - efa->e1->v2->co[2]) * (npct));
+
+ efa->e1->f1 = 32768*(npct);
+ efa->e1->v1->f |= 8;
+ efa->e1->v2->f |= 8;
+ a++;
+ }
+ if((efa->e2->f & 8) && a!=2)
+ {
+ float nlen,npct;
+
+ nlen = sqrt((efa->e2->v1->co[0] - efa->e2->v2->co[0])*(efa->e2->v1->co[0] - efa->e2->v2->co[0])+
+ (efa->e2->v1->co[1] - efa->e2->v2->co[1])*(efa->e2->v1->co[1] - efa->e2->v2->co[1])+
+ (efa->e2->v1->co[2] - efa->e2->v2->co[2])*(efa->e2->v1->co[2] - efa->e2->v2->co[2]));
+ npct = (percentcut*slen)/nlen;
+ if(npct >= 1) npct = 1;
+ if(efa->e2->f & 32) npct = 1-npct;
+
+ cen[a][0]= efa->e2->v1->co[0] - ((efa->e2->v1->co[0] - efa->e2->v2->co[0]) * (npct));
+ cen[a][1]= efa->e2->v1->co[1] - ((efa->e2->v1->co[1] - efa->e2->v2->co[1]) * (npct));
+ cen[a][2]= efa->e2->v1->co[2] - ((efa->e2->v1->co[2] - efa->e2->v2->co[2]) * (npct));
+
+ efa->e2->f1 = 32768*(npct);
+ efa->e2->v1->f |= 8;
+ efa->e2->v2->f |= 8;
+ a++;
+ }
+ if((efa->e3->f & 8) && a!=2){
+ float nlen,npct;
+
+ nlen = sqrt((efa->e3->v1->co[0] - efa->e3->v2->co[0])*(efa->e3->v1->co[0] - efa->e3->v2->co[0])+
+ (efa->e3->v1->co[1] - efa->e3->v2->co[1])*(efa->e3->v1->co[1] - efa->e3->v2->co[1])+
+ (efa->e3->v1->co[2] - efa->e3->v2->co[2])*(efa->e3->v1->co[2] - efa->e3->v2->co[2]));
+ npct = (percentcut*slen)/nlen;
+ if(npct >= 1) npct = 1;
+ if(efa->e3->f & 32) npct = 1-npct;
+
+ cen[a][0]= efa->e3->v1->co[0] - ((efa->e3->v1->co[0] - efa->e3->v2->co[0]) * (npct));
+ cen[a][1]= efa->e3->v1->co[1] - ((efa->e3->v1->co[1] - efa->e3->v2->co[1]) * (npct));
+ cen[a][2]= efa->e3->v1->co[2] - ((efa->e3->v1->co[2] - efa->e3->v2->co[2]) * (npct));
+
+ efa->e3->f1 = 32768*(npct);
+ efa->e3->v1->f |= 8;
+ efa->e3->v2->f |= 8;
+ a++;
+ }
+
+ if(efa->e4){
+ if((efa->e4->f & 8) && a!=2){
+ float nlen,npct;
+
+ nlen = sqrt((efa->e4->v1->co[0] - efa->e4->v2->co[0])*(efa->e4->v1->co[0] - efa->e4->v2->co[0])+
+ (efa->e4->v1->co[1] - efa->e4->v2->co[1])*(efa->e4->v1->co[1] - efa->e4->v2->co[1])+
+ (efa->e4->v1->co[2] - efa->e4->v2->co[2])*(efa->e4->v1->co[2] - efa->e4->v2->co[2]));
+ npct = (percentcut*slen)/nlen;
+ if(npct >= 1) npct = 1;
+ if(efa->e4->f & 32) npct = 1-npct;
+
+ cen[a][0]= efa->e4->v1->co[0] - ((efa->e4->v1->co[0] - efa->e4->v2->co[0]) * (npct));
+ cen[a][1]= efa->e4->v1->co[1] - ((efa->e4->v1->co[1] - efa->e4->v2->co[1]) * (npct));
+ cen[a][2]= efa->e4->v1->co[2] - ((efa->e4->v1->co[2] - efa->e4->v2->co[2]) * (npct));
+
+ efa->e4->f1 = 32768*(npct);
+ efa->e4->v1->f |= 8;
+ efa->e4->v2->f |= 8;
+ a++;
+ }
+ }
+ else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
+ if(!(efa->v1->f & 8) && efa->v1->h==0){
+ cen[a][0]= efa->v1->co[0];
+ cen[a][1]= efa->v1->co[1];
+ cen[a][2]= efa->v1->co[2];
+ a++;
+ }
+ else if(!(efa->v2->f & 8) && efa->v2->h==0){
+ cen[a][0]= efa->v2->co[0];
+ cen[a][1]= efa->v2->co[1];
+ cen[a][2]= efa->v2->co[2];
+ a++;
+ }
+ else if(!(efa->v3->f & 8) && efa->v3->h==0){
+ cen[a][0]= efa->v3->co[0];
+ cen[a][1]= efa->v3->co[1];
+ cen[a][2]= efa->v3->co[2];
+ a++;
+ }
+ }
+
+ if(a==2){
+ glBegin(GL_LINES);
+
+ glVertex3fv(cen[0]);
+ glVertex3fv(cen[1]);
+
+ glEnd();
+ }
+ }
+ }
+ }
+ /* restore matrix transform */
+
+ glPopMatrix();
+
+ /*--------- END Preview Lines------------*/
+ while(qtest())
+ {
+ unsigned 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 && (event==SKEY))
+ {
+ if(smooth)smooth = 0;
+ else smooth = 1;
+ }
+
+ if(val && (event==PKEY))
+ {
+ if(inset)inset = 0;
+ else inset = 1;
+ }
+
+ if(val && (event==FKEY))
+ {
+ int ct;
+ for(ct = 0; ct < ect; ct++){
+ if(tagged[ct]->f & 32)
+ tagged[ct]->f &= ~32;
+ else
+ tagged[ct]->f |= 32;
+ }
+ }
+
+ if(val && (event == MIDDLEMOUSE))
+ {
+ cut = 2;
+ searching=0;
+ }
+ else if(val && (event==LEFTMOUSE || event==RETKEY))
+ {
+ searching=0;
+ }
+
+ if(val && (event==ESCKEY || event==RIGHTMOUSE ))
+ {
+ searching=0;
+ cut = 0;
+ }
+
+ }
+
+
+ /* Determine the % on wich the loop should be cut */
+ getmouseco_areawin(mval);
+ v1[0]=(float)mval[0];
+ v1[1]=(float)mval[1];
+
+ v2[0]=(float)start->v1->xs;
+ v2[1]=(float)start->v1->ys;
+
+ v3[0]=(float)start->v2->xs;
+ v3[1]=(float)start->v2->ys;
+
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
+ len= rc[0]*rc[0]+ rc[1]*rc[1];
+
+ labda= ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
+
+
+ if(labda<=0.0) labda=0.0;
+ else if(labda>=1.0)labda=1.0;
+
+ percentcut=labda;
+
+ if(start->f & 32)
+ percentcut = 1.0-percentcut;
+
+ if(cut == 2){
+ percentcut = 0.5;
+ }
+
+ if (G.qual & LR_SHIFTKEY){
+
+ percentcut = (int)(percentcut*100.0)/100.0;
+ }
+ else if (G.qual & LR_CTRLKEY)
+ percentcut = (int)(percentcut*10.0)/10.0;
+
+ outcut = (percentcut*100.0);
+
+ /* Build the Header Line */
+
+ if(inset)
+ sprintf(mesg,"Cut: %0.2f%% ",slen*percentcut);
+ else
+ sprintf(mesg,"Cut: %0.2f%% ",outcut);
+
+
+ if(smooth)
+ sprintf(mesg,"%s| (f)lip side | (s)mooth on |",mesg);
+ else
+ sprintf(mesg,"%s| (f)lip side | (s)mooth off |",mesg);
+
+ if(inset)
+ sprintf(mesg,"%s (p)roportional on ",mesg);
+ else
+ sprintf(mesg,"%s (p)roportional off",mesg);
+
+ headerprint(mesg);
+
+ screen_swapbuffers();
+ }
+
+ if(cut){
+ /* Now that we have selected a cut %, mark the edges for cutting. */
+ if(!inset){
+ for(eed = em->edges.first; eed; eed=eed->next){
+ if(percentcut == 1.0)
+ percentcut = 0.9999;
+ else if(percentcut == 0.0)
+ percentcut = 0.0001;
+ if(eed->f & 8){
+ if(eed->f & 32)/* Need to offset by a const. (0.5/32768) for consistant roundoff */
+ eed->f1 = 32768*(1.0-percentcut - 0.0000153);
+ else
+ eed->f1 = 32768*(percentcut + 0.0000153);
+ }
+ }
+ }
+ /*-------------------------------------*/
+
+ if(smooth)
+ subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD | B_SMOOTH); /* B_KNIFE tells subdivide that edgeflags are already set */
+ else
+ subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD); /* B_KNIFE tells subdivide that edgeflags are already set */
+
+ for(eed = em->edges.first; eed; eed=eed->next){
+ if(eed->v1->f & 16) eed->v1->f |= 1;
+ else eed->v1->f &= ~1;
+
+ if(eed->v2->f & 16) eed->v2->f |= 1;
+ else eed->v2->f &= ~1;
+ }
+ }
+ }
+ /*----------END Cut Loop-----------------------------*/
+
+
+
+ /* Clear flags */
+ for(eed = em->edges.first; eed; eed=eed->next){
+ eed->f &= ~(2|4|8|32|64);
+ eed->v1->f &= ~(2|16);
+ eed->v2->f &= ~(2|16);
+ }
+
+ for(efa= em->faces.first; efa; efa=efa->next){
+ efa->f &= ~(4|8);
+ }
+
+ countall();
+
+ if(tagged)
+ MEM_freeN(tagged);
+ if(taggedsrch)
+ MEM_freeN(taggedsrch);
+ if(percentfacesloop)
+ MEM_freeN(percentfacesloop);
+
+ /* send event to redraw this window, does header too */
+ SetBlenderCursor(SYSCURSOR);
+ addqueue(curarea->win, REDRAW, 1);
+}
+
+/* ****************************** END LOOPOPERATIONS ********************** */
+
+void LoopMenu(){ /* Called by KKey */
+
+ short ret;
+
+ ret=pupmenu("Loop/Cut Menu %t|Face Loop Select %x1|Face Loop Cut %x2|"
+ "Knife (Exact) %x3|Knife (Midpoints)%x4|");
+
+ switch (ret){
+ case 1:
+ loopoperations(LOOP_SELECT);
+ break;
+ case 2:
+ loopoperations(LOOP_CUT);
+ break;
+ case 3:
+ KnifeSubdivide(KNIFE_EXACT);
+ break;
+ case 4:
+ KnifeSubdivide(KNIFE_MIDPOINT);
+ }
+
+}
+
diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c
new file mode 100644
index 00000000000..f711b90317b
--- /dev/null
+++ b/source/blender/src/editmesh_mods.c
@@ -0,0 +1,1447 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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 NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_mods.c, UI level access, no geometry changes
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_resources.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "render.h" // externtex, badlevel call (ton)
+
+#include "editmesh.h"
+
+/* **************************** MODS ************************* */
+
+void selectswap_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->h==0) {
+ if(eve->f & 1) eve->f&= ~1;
+ else eve->f|= 1;
+ }
+ eve= eve->next;
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+
+}
+
+
+
+
+void deselectall_mesh(void) /* toggle */
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int a;
+
+ if(G.obedit->lay & G.vd->lay) {
+ a= 0;
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ a= 1;
+ break;
+ }
+ eve= eve->next;
+ }
+
+ if (a) undo_push_mesh("Deselect All");
+ else undo_push_mesh("Select All");
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->h==0) {
+ if(a) eve->f&= -2;
+ else eve->f|= 1;
+ }
+ eve= eve->next;
+ }
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+void righthandfaces(int select) /* makes faces righthand turning */
+{
+ EditMesh *em = G.editMesh;
+ 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->f= 0;
+ eed->f1= 0;
+ eed= eed->next;
+ }
+
+ /* count faces and edges */
+ totsel= 0;
+ efa= em->faces.first;
+ while(efa) {
+ if(select==0 || faceselectedAND(efa, 1) ) {
+ efa->f= 1;
+ totsel++;
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->v4) efa->e4->f1++;
+ }
+ else efa->f= 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->f) {
+ CalcCent3f(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) {
+ CalcCent3f(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;
+ }
+
+ /* set first face correct: calc normal */
+
+ if(tria_nr==1) {
+ CalcNormFloat(startvl->v1->co, startvl->v3->co, startvl->v4->co, nor);
+ CalcCent3f(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
+ } else {
+ CalcNormFloat(startvl->v1->co, startvl->v2->co, startvl->v3->co, nor);
+ CalcCent3f(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
+ }
+ /* first normal is oriented this way or the other */
+ if(select) {
+ if(select==2) {
+ if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipface(startvl);
+ }
+ else {
+ if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
+ }
+ }
+ else if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
+
+
+ eed= startvl->e1;
+ if(eed->v1==startvl->v1) eed->f= 1;
+ else eed->f= 2;
+
+ eed= startvl->e2;
+ if(eed->v1==startvl->v2) eed->f= 1;
+ else eed->f= 2;
+
+ eed= startvl->e3;
+ if(eed->v1==startvl->v3) eed->f= 1;
+ else eed->f= 2;
+
+ eed= startvl->e4;
+ if(eed) {
+ if(eed->v1==startvl->v4) eed->f= 1;
+ else eed->f= 2;
+ }
+
+ startvl->f= 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->f) {
+ turn= 0;
+ foundone= 0;
+
+ ed1= efa->e1;
+ ed2= efa->e2;
+ ed3= efa->e3;
+ ed4= efa->e4;
+
+ if(ed1->f) {
+ if(ed1->v1==efa->v1 && ed1->f==1) turn= 1;
+ if(ed1->v2==efa->v1 && ed1->f==2) turn= 1;
+ foundone= 1;
+ }
+ else if(ed2->f) {
+ if(ed2->v1==efa->v2 && ed2->f==1) turn= 1;
+ if(ed2->v2==efa->v2 && ed2->f==2) turn= 1;
+ foundone= 1;
+ }
+ else if(ed3->f) {
+ if(ed3->v1==efa->v3 && ed3->f==1) turn= 1;
+ if(ed3->v2==efa->v3 && ed3->f==2) turn= 1;
+ foundone= 1;
+ }
+ else if(ed4 && ed4->f) {
+ if(ed4->v1==efa->v4 && ed4->f==1) turn= 1;
+ if(ed4->v2==efa->v4 && ed4->f==2) turn= 1;
+ foundone= 1;
+ }
+
+ if(foundone) {
+ found= 1;
+ totsel--;
+ efa->f= 0;
+
+ if(turn) {
+ if(ed1->v1==efa->v1) ed1->f= 2;
+ else ed1->f= 1;
+ if(ed2->v1==efa->v2) ed2->f= 2;
+ else ed2->f= 1;
+ if(ed3->v1==efa->v3) ed3->f= 2;
+ else ed3->f= 1;
+ if(ed4) {
+ if(ed4->v1==efa->v4) ed4->f= 2;
+ else ed4->f= 1;
+ }
+
+ flipface(efa);
+
+ }
+ else {
+ if(ed1->v1== efa->v1) ed1->f= 1;
+ else ed1->f= 2;
+ if(ed2->v1==efa->v2) ed2->f= 1;
+ else ed2->f= 2;
+ if(ed3->v1==efa->v3) ed3->f= 1;
+ else ed3->f= 2;
+ if(ed4) {
+ if(ed4->v1==efa->v4) ed4->f= 1;
+ else ed4->f= 2;
+ }
+ }
+ }
+ }
+ if(direct) efa= efa->next;
+ else efa= efa->prev;
+ }
+ direct= 1-direct;
+ }
+ }
+
+ recalc_editnormals();
+
+ makeDispList(G.obedit);
+
+ waitcursor(0);
+}
+
+static EditVert *findnearestvert(short sel)
+{
+ EditMesh *em = G.editMesh;
+ /* if sel==1 the vertices with flag==1 get a disadvantage */
+ EditVert *eve,*act=0;
+ static EditVert *acto=0;
+ short dist=100,temp,mval[2];
+
+ if(em->verts.first==0) return 0;
+
+ /* do projection */
+ calc_meshverts_ext(); /* drawobject.c */
+
+ /* we count from acto->next to last, and from first to acto */
+ /* does acto exist? */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve==acto) break;
+ eve= eve->next;
+ }
+ if(eve==0) acto= em->verts.first;
+
+ if(acto==0) return 0;
+
+ /* is there an indicated vertex? part 1 */
+ getmouseco_areawin(mval);
+ eve= acto->next;
+ while(eve) {
+ if(eve->h==0) {
+ temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys);
+ if( (eve->f & 1)==sel ) temp+=5;
+ if(temp<dist) {
+ act= eve;
+ dist= temp;
+ if(dist<4) break;
+ }
+ }
+ eve= eve->next;
+ }
+ /* is there an indicated vertex? part 2 */
+ if(dist>3) {
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->h==0) {
+ temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys);
+ if( (eve->f & 1)==sel ) temp+=5;
+ if(temp<dist) {
+ act= eve;
+ if(temp<4) break;
+ dist= temp;
+ }
+ if(eve== acto) break;
+ }
+ eve= eve->next;
+ }
+ }
+
+ acto= act;
+ return act;
+}
+
+
+EditEdge *findnearestedge()
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *closest, *eed;
+ EditVert *eve;
+ short found=0, mval[2];
+ float distance[2], v1[2], v2[2], mval2[2];
+
+ if(em->edges.first==0) return NULL;
+ else eed=em->edges.first;
+
+ /* reset flags */
+ for(eve=em->verts.first; eve; eve=eve->next){
+ eve->f &= ~2;
+ }
+
+ calc_meshverts_ext_f2(); /*sets (eve->f & 2) for vertices that aren't visible*/
+ getmouseco_areawin(mval);
+ closest=NULL;
+
+ mval2[0] = (float)mval[0];
+ mval2[1] = (float)mval[1];
+
+ eed=em->edges.first;
+ /*compare the distance to the rest of the edges and find the closest one*/
+ while(eed) {
+ /* Are both vertices of the edge ofscreen or either of them hidden? then don't select the edge*/
+ if( !((eed->v1->f & 2) && (eed->v2->f & 2)) && (eed->v1->h==0 && eed->v2->h==0)){
+ v1[0] = eed->v1->xs;
+ v1[1] = eed->v1->ys;
+ v2[0] = eed->v2->xs;
+ v2[1] = eed->v2->ys;
+
+ distance[1] = PdistVL2Dfl(mval2, v1, v2);
+
+ if(distance[1]<50){
+ /*do we have to compare it to other distances? */
+ if(found) {
+ if (distance[1]<distance[0]){
+ distance[0]=distance[1];
+ /*save the current closest edge*/
+ closest=eed;
+ }
+ } else {
+ distance[0]=distance[1];
+ closest=eed;
+ found=1;
+ }
+ }
+ }
+ eed= eed->next;
+ }
+
+ /* reset flags */
+ for(eve=em->verts.first; eve; eve=eve->next){
+ eve->f &= ~2;
+ }
+
+ if(found) return closest;
+ else return 0;
+}
+
+static void edge_select(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *closest=0;
+
+ closest=findnearestedge();
+
+ if(closest){ /* Did we find anything that is selectable?*/
+
+ if( (G.qual & LR_SHIFTKEY)==0) {
+ EditVert *eve;
+
+ undo_push_mesh("Select Edge");
+ /* deselectall */
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f&= ~1;
+
+ /* select edge */
+ closest->v1->f |= 1;
+ closest->v2->f |= 1;
+ }
+ else {
+ /* both of the vertices are selected: deselect both*/
+ if((closest->v1->f & 1) && (closest->v2->f & 1) ){
+ closest->v1->f &= ~1;
+ closest->v2->f &= ~1;
+ }
+ else {
+ /* select both */
+ closest->v1->f |= 1;
+ closest->v2->f |= 1;
+ }
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+static void draw_vertices_special(int mode, EditVert *act) /* teken = draw */
+{
+ /* (only this view, no other windows) */
+ /* hackish routine for visual speed:
+ * mode 0: deselect the selected ones, draw them, except act
+ * mode 1: only draw act
+ */
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ float size= BIF_GetThemeValuef(TH_VERTEX_SIZE);
+ char col[3];
+
+ glPointSize(size);
+
+ persp(PERSP_VIEW);
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
+
+ if(mode==0) {
+ BIF_ThemeColor(TH_VERTEX);
+
+ /* set zbuffer on, its default off outside main drawloops */
+ if(G.vd->drawtype > OB_WIRE) {
+ G.zbuf= 1;
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ glBegin(GL_POINTS);
+ eve= (EditVert *)em->verts.first;
+ while(eve) {
+ if(eve->h==0) {
+ if(eve!=act && (eve->f & 1)) {
+ eve->f -= 1;
+ glVertex3fv(eve->co);
+ }
+ }
+ eve= eve->next;
+ }
+ glEnd();
+
+ glDisable(GL_DEPTH_TEST);
+ G.zbuf= 0;
+ }
+
+ /* draw active vertex */
+ if(act->f & 1) BIF_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
+ else BIF_GetThemeColor3ubv(TH_VERTEX, col);
+
+ glColor3ub(col[0], col[1], col[2]);
+
+ glBegin(GL_POINTS);
+ glVertex3fv(act->co);
+ glEnd();
+
+ glPointSize(1.0);
+ glPopMatrix();
+
+
+}
+
+void mouse_mesh(void)
+{
+ EditVert *act=0;
+
+ if(G.qual & LR_ALTKEY) {
+ if (G.qual & LR_CTRLKEY) edge_select();
+ }
+ else {
+
+ act= findnearestvert(1);
+ if(act) {
+
+ glDrawBuffer(GL_FRONT);
+
+ undo_push_mesh("Select Vertex");
+
+ if( (act->f & 1)==0) act->f+= 1;
+ else if(G.qual & LR_SHIFTKEY) act->f-= 1;
+
+ if((G.qual & LR_SHIFTKEY)==0) {
+ draw_vertices_special(0, act);
+ }
+ else draw_vertices_special(1, act);
+
+ countall();
+
+ glFlush();
+ glDrawBuffer(GL_BACK);
+
+ /* signal that frontbuf differs from back */
+ curarea->win_swap= WIN_FRONT_OK;
+
+ if(G.f & (G_FACESELECT|G_DRAWFACES|G_DRAWEDGES)) {
+ /* update full view later on */
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else allqueue(REDRAWVIEW3D, curarea->win); // all windows except this one
+ }
+
+ rightmouse_transform();
+ }
+}
+
+
+
+
+static void selectconnectedAll(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1,*v2;
+ EditEdge *eed;
+ short flag=1,toggle=0;
+
+ if(em->edges.first==0) return;
+
+ undo_push_mesh("Select Connected (All)");
+
+ while(flag==1) {
+ flag= 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 & 1) {
+ if( (v2->f & 1)==0 ) {
+ v2->f |= 1;
+ flag= 1;
+ }
+ }
+ else if(v2->f & 1) {
+ if( (v1->f & 1)==0 ) {
+ v1->f |= 1;
+ flag= 1;
+ }
+ }
+ }
+ if(toggle & 1) eed= eed->next;
+ else eed= eed->prev;
+ }
+ }
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+
+}
+
+void selectconnected_mesh(int qual)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1,*v2,*act= 0;
+ EditEdge *eed;
+ short flag=1,sel,toggle=0;
+
+ if(em->edges.first==0) return;
+
+ if(qual & LR_CTRLKEY) {
+ selectconnectedAll();
+ return;
+ }
+
+ sel= 3;
+ if(qual & LR_SHIFTKEY) sel=2;
+
+ act= findnearestvert(sel-2);
+ if(act==0) {
+ error("Nothing indicated ");
+ return;
+ }
+
+ undo_push_mesh("Select Linked");
+ /* clear test flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f&= ~2;
+ eve= eve->next;
+ }
+ act->f= (act->f & ~3) | sel;
+
+ while(flag==1) {
+ flag= 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 & 2) {
+ if( (v2->f & 2)==0 ) {
+ v2->f= (v2->f & ~3) | sel;
+ flag= 1;
+ }
+ }
+ else if(v2->f & 2) {
+ if( (v1->f & 2)==0 ) {
+ v1->f= (v1->f & ~3) | sel;
+ flag= 1;
+ }
+ }
+ }
+ if(toggle & 1) eed= eed->next;
+ else eed= eed->prev;
+ }
+ }
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+void vertexsmooth(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ float *adror, *adr, fac;
+ float fvec[3];
+ int teller=0;
+
+ if(G.obedit==0) return;
+
+ /* count */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) teller++;
+ eve= eve->next;
+ }
+ if(teller==0) return;
+
+ undo_push_mesh("Smooth");
+
+ adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ eve->vn= (EditVert *)adr;
+ eve->f1= 0;
+ adr+= 3;
+ }
+ eve= eve->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ if( (eed->v1->f & 1) || (eed->v2->f & 1) ) {
+ fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0;
+ fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0;
+ fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0;
+
+ if((eed->v1->f & 1) && eed->v1->f1<255) {
+ eed->v1->f1++;
+ VecAddf((float *)eed->v1->vn, (float *)eed->v1->vn, fvec);
+ }
+ if((eed->v2->f & 1) && eed->v2->f1<255) {
+ eed->v2->f1++;
+ VecAddf((float *)eed->v2->vn, (float *)eed->v2->vn, fvec);
+ }
+ }
+ eed= eed->next;
+ }
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ if(eve->f1) {
+ adr= (float *)eve->vn;
+ fac= 0.5/(float)eve->f1;
+
+ eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
+ eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
+ eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
+ }
+ eve->vn= 0;
+ }
+ eve= eve->next;
+ }
+ MEM_freeN(adror);
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+void vertexnoise(void)
+{
+ EditMesh *em = G.editMesh;
+ extern float Tin;
+ Material *ma;
+ Tex *tex;
+ EditVert *eve;
+ float b2, ofs, vec[3];
+
+ if(G.obedit==0) return;
+
+ undo_push_mesh("Noise");
+
+ ma= give_current_material(G.obedit, G.obedit->actcol);
+ if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
+ return;
+ }
+ tex= ma->mtex[0]->tex;
+
+ ofs= tex->turbul/200.0;
+
+ eve= (struct EditVert *)em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+
+ if(tex->type==TEX_STUCCI) {
+
+ b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
+ if(tex->stype) ofs*=(b2*b2);
+ vec[0]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
+ vec[1]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
+ vec[2]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
+
+ VecAddf(eve->co, eve->co, vec);
+ }
+ else {
+
+ externtex(ma->mtex[0], eve->co);
+
+ eve->co[2]+= 0.05*Tin;
+ }
+ }
+ eve= eve->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+void hide_mesh(int swap)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+
+ if(G.obedit==0) return;
+
+ if(swap) {
+ eve= em->verts.first;
+ while(eve) {
+ if((eve->f & 1)==0) {
+ eve->xs= 3200;
+ eve->h= 1;
+ }
+ eve= eve->next;
+ }
+ }
+ else {
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ eve->f-=1;
+ eve->xs= 3200;
+ eve->h= 1;
+ }
+ eve= eve->next;
+ }
+ }
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->v1->h || eed->v2->h) eed->h= 1;
+ else eed->h= 0;
+ eed= eed->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+
+void reveal_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+
+ if(G.obedit==0) return;
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->h) {
+ eve->h= 0;
+ eve->f|=1;
+ }
+ eve= eve->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->h= 0;
+ eed= eed->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+
+void vertices_to_sphere(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ Object *ob= OBACT;
+ float *curs, len, vec[3], cent[3], fac, facm, imat[3][3], bmat[3][3];
+ int tot;
+ short perc=100;
+
+ if(ob==0) return;
+ TEST_EDITMESH
+
+ if(button(&perc, 1, 100, "Percentage:")==0) return;
+
+ undo_push_mesh("To Sphere");
+
+ fac= perc/100.0;
+ facm= 1.0-fac;
+
+ Mat3CpyMat4(bmat, ob->obmat);
+ Mat3Inv(imat, bmat);
+
+ /* centre */
+ curs= give_cursor();
+ cent[0]= curs[0]-ob->obmat[3][0];
+ cent[1]= curs[1]-ob->obmat[3][1];
+ cent[2]= curs[2]-ob->obmat[3][2];
+ Mat3MulVecfl(imat, cent);
+
+ len= 0.0;
+ tot= 0;
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ tot++;
+ len+= VecLenf(cent, eve->co);
+ }
+ eve= eve->next;
+ }
+ len/=tot;
+
+ if(len==0.0) len= 10.0;
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ vec[0]= eve->co[0]-cent[0];
+ vec[1]= eve->co[1]-cent[1];
+ vec[2]= eve->co[2]-cent[2];
+
+ Normalise(vec);
+
+ eve->co[0]= fac*(cent[0]+vec[0]*len) + facm*eve->co[0];
+ eve->co[1]= fac*(cent[1]+vec[1]*len) + facm*eve->co[1];
+ eve->co[2]= fac*(cent[2]+vec[2]*len) + facm*eve->co[2];
+
+ }
+ eve= eve->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+
+/* ********** ALIGN WITH VIEW **************** */
+
+
+static void editmesh_calc_selvert_center(float cent_r[3])
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int nsel= 0;
+
+ cent_r[0]= cent_r[1]= cent_r[0]= 0.0;
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if (eve->f & SELECT) {
+ cent_r[0]+= eve->co[0];
+ cent_r[1]+= eve->co[1];
+ cent_r[2]+= eve->co[2];
+ nsel++;
+ }
+ }
+
+ if (nsel) {
+ cent_r[0]/= nsel;
+ cent_r[1]/= nsel;
+ cent_r[2]/= nsel;
+ }
+}
+
+static int tface_is_selected(TFace *tf)
+{
+ return (!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT));
+}
+
+static int faceselect_nfaces_selected(Mesh *me)
+{
+ int i, count= 0;
+
+ for (i=0; i<me->totface; i++) {
+ MFace *mf= ((MFace*) me->mface) + i;
+ TFace *tf= ((TFace*) me->tface) + i;
+
+ if (mf->v3 && tface_is_selected(tf))
+ count++;
+ }
+
+ return count;
+}
+
+ /* XXX, code for both these functions should be abstract,
+ * then unified, then written for other things (like objects,
+ * which would use same as vertices method), then added
+ * to interface! Hoera! - zr
+ */
+void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
+{
+ if (!faceselect_nfaces_selected(me)) {
+ error("No faces selected.");
+ } else {
+ float norm[3];
+ int i;
+
+ norm[0]= norm[1]= norm[2]= 0.0;
+ for (i=0; i<me->totface; i++) {
+ MFace *mf= ((MFace*) me->mface) + i;
+ TFace *tf= ((TFace*) me->tface) + i;
+
+ if (mf->v3 && tface_is_selected(tf)) {
+ float *v1, *v2, *v3, fno[3];
+
+ v1= me->mvert[mf->v1].co;
+ v2= me->mvert[mf->v2].co;
+ v3= me->mvert[mf->v3].co;
+ if (mf->v4) {
+ float *v4= me->mvert[mf->v4].co;
+ CalcNormFloat4(v1, v2, v3, v4, fno);
+ } else {
+ CalcNormFloat(v1, v2, v3, fno);
+ }
+
+ norm[0]+= fno[0];
+ norm[1]+= fno[1];
+ norm[2]+= fno[2];
+ }
+ }
+
+ view3d_align_axis_to_vector(v3d, axis, norm);
+ }
+}
+
+void editmesh_align_view_to_selected(View3D *v3d, int axis)
+{
+ EditMesh *em = G.editMesh;
+ int nselverts= editmesh_nvertices_selected();
+
+ if (nselverts<3) {
+ if (nselverts==0) {
+ error("No faces or vertices selected.");
+ } else {
+ error("At least one face or three vertices must be selected.");
+ }
+ } else if (editmesh_nfaces_selected()) {
+ float norm[3];
+ EditFace *efa;
+
+ norm[0]= norm[1]= norm[2]= 0.0;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (faceselectedAND(efa, SELECT)) {
+ float fno[3];
+ if (efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, fno);
+ else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, fno);
+ /* XXX, fixme, should be flipped intp a
+ * consistent direction. -zr
+ */
+ norm[0]+= fno[0];
+ norm[1]+= fno[1];
+ norm[2]+= fno[2];
+ }
+ }
+
+ Mat4Mul3Vecfl(G.obedit->obmat, norm);
+ view3d_align_axis_to_vector(v3d, axis, norm);
+ } else {
+ float cent[3], norm[3];
+ EditVert *eve, *leve= NULL;
+
+ norm[0]= norm[1]= norm[2]= 0.0;
+ editmesh_calc_selvert_center(cent);
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if (eve->f & SELECT) {
+ if (leve) {
+ float tno[3];
+ CalcNormFloat(cent, leve->co, eve->co, tno);
+
+ /* XXX, fixme, should be flipped intp a
+ * consistent direction. -zr
+ */
+ norm[0]+= tno[0];
+ norm[1]+= tno[1];
+ norm[2]+= tno[2];
+ }
+ leve= eve;
+ }
+ }
+
+ Mat4Mul3Vecfl(G.obedit->obmat, norm);
+ view3d_align_axis_to_vector(v3d, axis, norm);
+ }
+}
+
+
+void select_non_manifold(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ /* Selects isolated verts, and edges that do not have 2 neighboring
+ * faces
+ */
+
+
+ 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->f1 != 2) {
+ if (!eed->v1->h) eed->v1->f |= 1;
+ if (!eed->v2->h) eed->v2->f |= 1;
+ }
+ eed= eed->next;
+ }
+
+ /* select isolated verts */
+ eve= em->verts.first;
+ while(eve) {
+ if (eve->f1 == 0) {
+ if (!eve->h) eve->f |= 1;
+ }
+ eve= eve->next;
+ }
+
+ countall();
+ addqueue(curarea->win, REDRAW, 0);
+
+}
+
+void select_more(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+
+ eve= em->verts.first;
+ while(eve) {
+ eve->f1 = 0;
+ eve= eve->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ if (eed->v1->f & 1)
+ eed->v2->f1 = 1;
+ if (eed->v2->f & 1)
+ eed->v1->f1 = 1;
+
+ eed= eed->next;
+ }
+
+ eve= em->verts.first;
+ while(eve) {
+ if (eve->f1 == 1)
+ if (!eve->h) eve->f |= 1;
+
+ eve= eve->next;
+ }
+
+ countall();
+ addqueue(curarea->win, REDRAW, 0);
+}
+
+void select_less(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ /* eve->f1 & 1 => isolated */
+ /* eve->f1 & 2 => on an edge */
+ /* eve->f1 & 4 => shares edge with a deselected vert */
+ /* eve->f1 & 8 => at most one neighbor */
+
+ eve= em->verts.first;
+ while(eve) {
+ /* assume vert is isolated unless proven otherwise, */
+ /* assume at most one neighbor too */
+ eve->f1 = 1 | 8;
+
+ eve= eve->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ /* this will count how many faces are connected to
+ * this edge */
+ eed->f1= 0;
+
+ /* if vert wasn't isolated, it now has more than one neighbor */
+ if (~eed->v1->f1 & 1) eed->v1->f1 &= ~8;
+ if (~eed->v2->f1 & 1) eed->v2->f1 &= ~8;
+
+ /* verts on edge are clearly not isolated */
+ eed->v1->f1 &= ~1;
+ eed->v2->f1 &= ~1;
+
+ /* if one of the verts on the edge is deselected,
+ * deselect the other */
+ if ( !(eed->v1->h) && (~eed->v1->f & 1) )
+ eed->v2->f1 |= 4;
+ if ( !(eed->v2->h) && (~eed->v2->f & 1) )
+ eed->v1->f1 |= 4;
+
+ 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;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ /* if the edge has only one neighboring face, then
+ * deselect attached verts */
+ if (eed->f1 == 1) {
+ eed->v1->f1 |= 2;
+ eed->v2->f1 |= 2;
+ }
+
+ eed= eed->next;
+ }
+
+ /* deselect verts */
+ eve= em->verts.first;
+ while(eve) {
+ if (eve->f1) {
+ eve->f &= ~1;
+ }
+
+ eve= eve->next;
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+void selectrandom_mesh(void) /* randomly selects a user-set % of vertices */
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int newsel = 0; /* to decide whether to redraw or not */
+ short randfac = 50;
+
+ if(G.obedit==0) return;
+
+ /* Get the percentage of vertices to randomly select as 'randfac' */
+ if(button(&randfac,0, 100,"Percentage:")==0) return;
+
+ if(G.obedit->lay & G.vd->lay) {
+ eve= em->verts.first;
+ while(eve) {
+ BLI_srand( BLI_rand() ); /* random seed */
+ if ( (BLI_frand() * 100) < randfac) {
+ eve->f |= SELECT;
+ newsel = 1;
+ } else {
+ /* Deselect other vertices
+ *
+ * - Commenting this out makes it add to the selection,
+ * rather than replace it.
+ * eve->f &= ~SELECT;
+ */
+ }
+ eve= eve->next;
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+
+
+void editmesh_select_by_material(int index)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ for (efa=em->faces.first; efa; efa= efa->next) {
+ if (efa->mat_nr==index) {
+ if(efa->v1->h==0) efa->v1->f |= 1;
+ if(efa->v2->h==0) efa->v2->f |= 1;
+ if(efa->v3->h==0) efa->v3->f |= 1;
+ if(efa->v4 && efa->v4->h==0) efa->v4->f |= 1;
+ }
+ }
+}
+
+void editmesh_deselect_by_material(int index)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ for (efa=em->faces.first; efa; efa= efa->next) {
+ if (efa->mat_nr==index) {
+ if(efa->v1->h==0) efa->v1->f &= ~1;
+ if(efa->v2->h==0) efa->v2->f &= ~1;
+ if(efa->v3->h==0) efa->v3->f &= ~1;
+ if(efa->v4 && efa->v4->h==0) efa->v4->f &= ~1;
+ }
+ }
+}
+
+void editmesh_mark_seam(int clear)
+{
+ EditMesh *em= G.editMesh;
+ EditEdge *eed;
+ Mesh *me= G.obedit->data;
+
+ /* auto-enable seams drawing */
+ if(clear==0) {
+ if(!(G.f & G_DRAWSEAMS)) {
+ G.f |= G_DRAWSEAMS;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ if(!me->medge)
+ me->medge= MEM_callocN(sizeof(MEdge), "fake mesh edge");
+ }
+
+ if(clear) {
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) {
+ eed->seam = 0;
+ }
+ eed= eed->next;
+ }
+ }
+ else {
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) {
+ eed->seam = 1;
+ }
+ eed= eed->next;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void Edge_Menu() {
+ short ret;
+
+ ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edges %x3");
+
+ switch(ret)
+ {
+ case 1:
+ editmesh_mark_seam(0);
+ break;
+ case 2:
+ editmesh_mark_seam(1);
+ break;
+ case 3:
+ edge_rotate_selected();
+ break;
+ }
+}
+
+
diff --git a/source/blender/src/editmesh_tools.c b/source/blender/src/editmesh_tools.c
new file mode 100644
index 00000000000..f72c6250809
--- /dev/null
+++ b/source/blender/src/editmesh_tools.c
@@ -0,0 +1,3446 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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 NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_cursors.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_resources.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "editmesh.h"
+
+
+/********* qsort routines *********/
+
+
+struct xvertsort {
+ float x;
+ EditVert *v1;
+};
+
+static int vergxco(const void *v1, const void *v2)
+{
+ const struct xvertsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+struct facesort {
+ long 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;
+}
+
+
+/* *********************************** */
+
+void convert_to_triface(int all)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *efan, *next;
+
+ undo_push_mesh("Convert Quads to Triangles");
+
+ efa= em->faces.first;
+ while(efa) {
+ next= efa->next;
+ if(efa->v4) {
+ if(all || faceselectedAND(efa, 1) ) {
+
+ efan= addfacelist(efa->v1, efa->v2, efa->v3, 0, efa);
+ efan= addfacelist(efa->v1, efa->v3, efa->v4, 0, efa);
+
+ efan->tf.uv[1][0]= efan->tf.uv[2][0];
+ efan->tf.uv[1][1]= efan->tf.uv[2][1];
+ efan->tf.uv[2][0]= efan->tf.uv[3][0];
+ efan->tf.uv[2][1]= efan->tf.uv[3][1];
+
+ efan->tf.col[1]= efan->tf.col[2];
+ efan->tf.col[2]= efan->tf.col[3];
+
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ }
+ efa= next;
+ }
+
+}
+
+
+short removedoublesflag(short flag, float limit) /* return amount */
+{
+ EditMesh *em = G.editMesh;
+ /* all verts with (flag & 'flag') are being evaluated */
+ EditVert *eve, *v1, *nextve;
+ EditEdge *eed, *e1, *nexted;
+ EditFace *efa, *nextvl;
+ struct xvertsort *sortblock, *sb, *sb1;
+ struct facesort *vlsortblock, *vsb, *vsb1;
+ float dist;
+ int a, b, test, aantal;
+
+ /* flag 128 is cleared, count */
+ eve= em->verts.first;
+ aantal= 0;
+ while(eve) {
+ eve->f&= ~128;
+ if(eve->f & flag) aantal++;
+ eve= eve->next;
+ }
+ if(aantal==0) return 0;
+
+ /* allocate memory and qsort */
+ sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) {
+ sb->x= eve->co[0]+eve->co[1]+eve->co[2];
+ sb->v1= eve;
+ sb++;
+ }
+ eve= eve->next;
+ }
+ qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco);
+
+ /* test for doubles */
+ sb= sortblock;
+ for(a=0; a<aantal; a++) {
+ eve= sb->v1;
+ if( (eve->f & 128)==0 ) {
+ sb1= sb+1;
+ for(b=a+1; b<aantal; b++) {
+ /* first test: simpel dist */
+ dist= sb1->x - sb->x;
+ if(dist > limit) break;
+
+ /* second test: is vertex allowed */
+ v1= sb1->v1;
+ if( (v1->f & 128)==0 ) {
+
+ dist= fabs(v1->co[0]-eve->co[0]);
+ if(dist<=limit) {
+ dist= fabs(v1->co[1]-eve->co[1]);
+ if(dist<=limit) {
+ dist= fabs(v1->co[2]-eve->co[2]);
+ if(dist<=limit) {
+ v1->f|= 128;
+ v1->vn= eve;
+ }
+ }
+ }
+ }
+ sb1++;
+ }
+ }
+ sb++;
+ }
+ MEM_freeN(sortblock);
+
+ /* test edges and insert again */
+ eed= em->edges.first;
+ while(eed) {
+ eed->f= 0;
+ eed= eed->next;
+ }
+ eed= em->edges.last;
+ while(eed) {
+ nexted= eed->prev;
+
+ if(eed->f==0) {
+ if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
+ remedge(eed);
+
+ if(eed->v1->f & 128) eed->v1= eed->v1->vn;
+ if(eed->v2->f & 128) eed->v2= eed->v2->vn;
+ e1= addedgelist(eed->v1, eed->v2, eed);
+
+ if(e1) e1->f= 1;
+ if(e1!=eed) free_editedge(eed);
+ }
+ }
+ eed= nexted;
+ }
+
+ /* first count amount of test faces */
+ efa= (struct EditFace *)em->faces.first;
+ aantal= 0;
+ while(efa) {
+ efa->f= 0;
+ if(efa->v1->f & 128) efa->f= 1;
+ else if(efa->v2->f & 128) efa->f= 1;
+ else if(efa->v3->f & 128) efa->f= 1;
+ else if(efa->v4 && (efa->v4->f & 128)) efa->f= 1;
+
+ if(efa->f==1) aantal++;
+ 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->f==1) {
+
+ if(efa->v1->f & 128) efa->v1= efa->v1->vn;
+ if(efa->v2->f & 128) efa->v2= efa->v2->vn;
+ if(efa->v3->f & 128) efa->v3= efa->v3->vn;
+ if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->vn;
+
+ 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;
+ test= 0;
+ }
+ else if(test==8 || test==16) {
+ efa->v4= 0;
+ test= 0;
+ }
+ else {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ aantal--;
+ }
+ }
+ else {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ aantal--;
+ }
+ }
+
+ if(test==0) {
+ /* set edge pointers */
+ efa->e1= findedgelist(efa->v1, efa->v2);
+ efa->e2= findedgelist(efa->v2, efa->v3);
+ if(efa->v4==0) {
+ efa->e3= findedgelist(efa->v3, efa->v1);
+ efa->e4= 0;
+ }
+ else {
+ efa->e3= findedgelist(efa->v3, efa->v4);
+ efa->e4= findedgelist(efa->v4, efa->v1);
+ }
+ }
+ }
+ efa= nextvl;
+ }
+
+ /* double faces: sort block */
+ /* count again, now all selected faces */
+ aantal= 0;
+ efa= em->faces.first;
+ while(efa) {
+ efa->f= 0;
+ if(faceselectedAND(efa, 1)) {
+ efa->f= 1;
+ aantal++;
+ }
+ efa= efa->next;
+ }
+
+ if(aantal) {
+ /* double faces: sort block */
+ vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*aantal, "sortremovedoub");
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f & 1) {
+ if(efa->v4) vsb->x= (long) MIN4( (long)efa->v1, (long)efa->v2, (long)efa->v3, (long)efa->v4);
+ else vsb->x= (long) MIN3( (long)efa->v1, (long)efa->v2, (long)efa->v3);
+
+ vsb->efa= efa;
+ vsb++;
+ }
+ efa= efa->next;
+ }
+
+ qsort(vlsortblock, aantal, sizeof(struct facesort), vergface);
+
+ vsb= vlsortblock;
+ for(a=0; a<aantal; a++) {
+ efa= vsb->efa;
+ if( (efa->f & 128)==0 ) {
+ vsb1= vsb+1;
+
+ for(b=a+1; b<aantal; b++) {
+
+ /* first test: same pointer? */
+ if(vsb->x != vsb1->x) break;
+
+ /* second test: is test permitted? */
+ efa= vsb1->efa;
+ if( (efa->f & 128)==0 ) {
+ if( compareface(efa, vsb->efa)) efa->f |= 128;
+
+ }
+ vsb1++;
+ }
+ }
+ vsb++;
+ }
+
+ MEM_freeN(vlsortblock);
+
+ /* remove double faces */
+ efa= (struct EditFace *)em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f & 128) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ }
+
+ /* remove double vertices */
+ a= 0;
+ eve= (struct EditVert *)em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f & flag) {
+ if(eve->f & 128) {
+ a++;
+ BLI_remlink(&em->verts, eve);
+ free_editvert(eve);
+ }
+ }
+ eve= nextve;
+ }
+ return a; /* amount */
+}
+
+/* called from buttons */
+void xsortvert_flag(int flag)
+{
+ EditMesh *em = G.editMesh;
+ /* all verts with (flag & 'flag') are sorted */
+ EditVert *eve;
+ struct xvertsort *sortblock, *sb;
+ ListBase tbase;
+ int aantal;
+
+ /* count */
+ eve= em->verts.first;
+ aantal= 0;
+ while(eve) {
+ if(eve->f & flag) aantal++;
+ eve= eve->next;
+ }
+ if(aantal==0) return;
+
+ undo_push_mesh("Xsort");
+
+ /* allocate memory and sort */
+ sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) {
+ sb->x= eve->xs;
+ sb->v1= eve;
+ sb++;
+ }
+ eve= eve->next;
+ }
+ qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco);
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ sb= sortblock;
+ while(aantal--) {
+ eve= sb->v1;
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ sb++;
+ }
+
+ addlisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+}
+
+/* called from buttons */
+void hashvert_flag(int flag)
+{
+ /* switch vertex order using hash table */
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ struct xvertsort *sortblock, *sb, onth, *newsort;
+ ListBase tbase;
+ int aantal, a, b;
+
+ /* count */
+ eve= em->verts.first;
+ aantal= 0;
+ while(eve) {
+ if(eve->f & flag) aantal++;
+ eve= eve->next;
+ }
+ if(aantal==0) return;
+
+ undo_push_mesh("Hash");
+
+ /* allocate memory */
+ sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"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<aantal; a++, sb++) {
+ b= aantal*BLI_drand();
+ if(b>=0 && b<aantal) {
+ newsort= sortblock+b;
+ onth= *sb;
+ *sb= *newsort;
+ *newsort= onth;
+ }
+ }
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ sb= sortblock;
+ while(aantal--) {
+ eve= sb->v1;
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ sb++;
+ }
+
+ addlisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+}
+
+void extrude_mesh(void)
+{
+ short a;
+
+ TEST_EDITMESH
+
+ if(okee("Extrude")==0) return;
+
+ waitcursor(1);
+ undo_push_mesh("Extrude");
+
+ a= extrudeflag(1,1);
+ waitcursor(0);
+ if(a==0) {
+ error("No valid vertices are selected");
+ }
+ else {
+ countall(); /* for G.totvert in calc_meshverts() */
+ calc_meshverts();
+ transform('d');
+ G.undo_edit_level--; /* to hide the transform from undo */
+ }
+
+}
+
+void split_mesh(void)
+{
+
+ TEST_EDITMESH
+
+ if(okee(" Split ")==0) return;
+
+ waitcursor(1);
+ undo_push_mesh("Split");
+ /* make duplicate first */
+ adduplicateflag(1);
+ /* old faces have 3x flag 128 set, delete them */
+ delfaceflag(128);
+
+ waitcursor(0);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+void extrude_repeat_mesh(int steps, float offs)
+{
+ float dvec[3], tmat[3][3], bmat[3][3];
+ short a,ok;
+
+ TEST_EDITMESH
+ waitcursor(1);
+
+ undo_push_mesh("Extrude Repeat");
+
+ /* dvec */
+ dvec[0]= G.vd->persinv[2][0];
+ dvec[1]= G.vd->persinv[2][1];
+ dvec[2]= G.vd->persinv[2][2];
+ Normalise(dvec);
+ dvec[0]*= offs;
+ dvec[1]*= offs;
+ dvec[2]*= offs;
+
+ /* base correction */
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(tmat, bmat);
+ Mat3MulVecfl(tmat, dvec);
+
+ for(a=0;a<steps;a++) {
+ ok= extrudeflag(1,1);
+ if(ok==0) {
+ error("No valid vertices are selected");
+ break;
+ }
+ translateflag(1, dvec);
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+ waitcursor(0);
+}
+
+void spin_mesh(int steps,int degr,float *dvec, int mode)
+{
+ extern short editbutflag;
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*nextve;
+ float *curs, 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;
+
+ TEST_EDITMESH
+
+ waitcursor(1);
+
+ undo_push_mesh("Spin");
+
+ /* imat and centre and size */
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat,bmat);
+
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
+ Mat3MulVecfl(imat, cent);
+
+ phi= degr*M_PI/360.0;
+ phi/= steps;
+ if(editbutflag & B_CLOCKWISE) phi= -phi;
+
+ if(dvec) {
+ n[0]=n[1]= 0.0;
+ n[2]= 1.0;
+ } else {
+ n[0]= G.vd->viewinv[2][0];
+ n[1]= G.vd->viewinv[2][1];
+ n[2]= G.vd->viewinv[2][2];
+ Normalise(n);
+ }
+
+ q[0]= cos(phi);
+ si= sin(phi);
+ q[1]= n[0]*si;
+ q[2]= n[1]*si;
+ q[3]= n[2]*si;
+ QuatToMat3(q, cmat);
+
+ Mat3MulMat3(tmat,cmat,bmat);
+ Mat3MulMat3(bmat,imat,tmat);
+
+ if(mode==0) if(editbutflag & B_KEEPORIG) adduplicateflag(1);
+ ok= 1;
+
+ for(a=0;a<steps;a++) {
+ if(mode==0) ok= extrudeflag(1,1);
+ else adduplicateflag(1);
+ if(ok==0) {
+ error("No valid vertices are selected");
+ break;
+ }
+ rotateflag(1, cent, bmat);
+ if(dvec) {
+ Mat3MulVecfl(bmat,dvec);
+ translateflag(1,dvec);
+ }
+ }
+
+ waitcursor(0);
+ if(ok==0) {
+ /* no vertices or only loose ones selected, remove duplicates */
+ eve= em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f & 1) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(eve);
+ }
+ eve= nextve;
+ }
+ }
+ countall();
+ recalc_editnormals();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+void screw_mesh(int steps,int turns)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1=0,*v2=0;
+ EditEdge *eed;
+ float dvec[3], nor[3];
+
+ TEST_EDITMESH
+
+ /* first condition: we need frontview! */
+ if(G.vd->view!=1) {
+ error("Must be in Front View");
+ return;
+ }
+
+ undo_push_mesh("Screw");
+
+ /* clear flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f1= 0;
+ eve= eve->next;
+ }
+ /* edges set flags in verts */
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->v1->f & 1) {
+ if(eed->v2->f & 1) {
+ /* watch: f1 is a byte */
+ if(eed->v1->f1<2) eed->v1->f1++;
+ if(eed->v2->f1<2) eed->v2->f1++;
+ }
+ }
+ eed= eed->next;
+ }
+ /* find two vertices with eve->f1==1, more or less is wrong */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f1==1) {
+ if(v1==0) v1= eve;
+ else if(v2==0) v2= eve;
+ else {
+ v1=0;
+ break;
+ }
+ }
+ eve= eve->next;
+ }
+ if(v1==0 || v2==0) {
+ error("No curve is selected");
+ return;
+ }
+
+ /* 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, G.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];
+ }
+
+ spin_mesh(turns*steps, turns*360, dvec, 0);
+
+}
+
+
+static void erase_edges(ListBase *l)
+{
+ EditEdge *ed, *nexted;
+
+ ed = (EditEdge *) l->first;
+ while(ed) {
+ nexted= ed->next;
+ if( (ed->v1->f & 1) || (ed->v2->f & 1) ) {
+ remedge(ed);
+ free_editedge(ed);
+ }
+ ed= nexted;
+ }
+}
+
+static void erase_faces(ListBase *l)
+{
+ EditFace *f, *nextf;
+
+ f = (EditFace *) l->first;
+
+ while(f) {
+ nextf= f->next;
+ if( faceselectedOR(f, 1) ) {
+ BLI_remlink(l, f);
+ free_editface(f);
+ }
+ f = nextf;
+ }
+}
+
+static void erase_vertices(ListBase *l)
+{
+ EditVert *v, *nextv;
+
+ v = (EditVert *) l->first;
+ while(v) {
+ nextv= v->next;
+ if(v->f & 1) {
+ BLI_remlink(l, v);
+ free_editvert(v);
+ }
+ v = nextv;
+ }
+}
+
+void delete_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *nextvl;
+ EditVert *eve,*nextve;
+ EditEdge *eed,*nexted;
+ short event;
+ int count;
+
+ TEST_EDITMESH
+
+ event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5");
+ if(event<1) return;
+
+ if(event==10 ) {
+ undo_push_mesh("Erase Vertices");
+ erase_edges(&em->edges);
+ erase_faces(&em->faces);
+ erase_vertices(&em->verts);
+ }
+ else if(event==4) {
+ undo_push_mesh("Erase Edges & Faces");
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ /* delete only faces with 2 or more vertices selected */
+ count= 0;
+ if(efa->v1->f & 1) count++;
+ if(efa->v2->f & 1) count++;
+ if(efa->v3->f & 1) count++;
+ if(efa->v4 && (efa->v4->f & 1)) count++;
+ if(count>1) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ event=0;
+ if( efa->v1->f & 1) event++;
+ if( efa->v2->f & 1) event++;
+ if( efa->v3->f & 1) event++;
+ if(efa->v4 && (efa->v4->f & 1)) event++;
+
+ if(event>1) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ }
+ else if(event==1) {
+ undo_push_mesh("Erase Edges");
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ event=0;
+ if( efa->v1->f & 1) event++;
+ if( efa->v2->f & 1) event++;
+ if( efa->v3->f & 1) event++;
+ if(efa->v4 && (efa->v4->f & 1)) event++;
+
+ if(event>1) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ /* to remove loose vertices: */
+ eed= em->edges.first;
+ while(eed) {
+ if( eed->v1->f & 1) eed->v1->f-=1;
+ if( eed->v2->f & 1) eed->v2->f-=1;
+ eed= eed->next;
+ }
+ eve= em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f & 1) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(eve);
+ }
+ eve= nextve;
+ }
+
+ }
+ else if(event==2) {
+ undo_push_mesh("Erase Faces");
+ delfaceflag(1);
+ }
+ else if(event==3) {
+ undo_push_mesh("Erase All");
+ if(em->verts.first) free_vertlist(&em->verts);
+ if(em->edges.first) free_edgelist(&em->edges);
+ if(em->faces.first) free_facelist(&em->faces);
+ }
+ else if(event==5) {
+ undo_push_mesh("Erase Only Faces");
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(faceselectedAND(efa, 1)) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+
+/* Got this from scanfill.c. You will need to juggle around the
+ * callbacks for the scanfill.c code a bit for this to work. */
+void fill_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1;
+ EditEdge *eed,*e1,*nexted;
+ EditFace *efa,*nextvl;
+ short ok;
+
+ if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return;
+
+ waitcursor(1);
+
+ undo_push_mesh("Fill");
+
+ /* copy all selected vertices */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ v1= BLI_addfillvert(eve->co);
+ eve->vn= v1;
+ v1->vn= eve;
+ v1->h= 0;
+ }
+ eve= eve->next;
+ }
+ /* copy all selected edges */
+ eed= em->edges.first;
+ while(eed) {
+ if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
+ e1= BLI_addfilledge(eed->v1->vn, eed->v2->vn);
+ e1->v1->h++;
+ e1->v2->h++;
+ }
+ eed= eed->next;
+ }
+ /* from all selected faces: remove vertices and edges verwijderen to prevent doubles */
+ /* all edges add values, faces subtract,
+ then remove edges with vertices ->h<2 */
+ efa= em->faces.first;
+ ok= 0;
+ while(efa) {
+ nextvl= efa->next;
+ if( faceselectedAND(efa, 1) ) {
+ efa->v1->vn->h--;
+ efa->v2->vn->h--;
+ efa->v3->vn->h--;
+ if(efa->v4) efa->v4->vn->h--;
+ ok= 1;
+
+ }
+ efa= nextvl;
+ }
+ if(ok) { /* there are faces selected */
+ eed= filledgebase.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->v1->h<2 || eed->v2->h<2) {
+ BLI_remlink(&filledgebase,eed);
+ }
+ eed= nexted;
+ }
+ }
+
+ /* to make edgefill work */
+ BLI_setScanFillObjectRef(G.obedit);
+ BLI_setScanFillColourRef(&G.obedit->actcol);
+
+ ok= BLI_edgefill(0);
+
+ /* printf("time: %d\n",(clock()-tijd)/1000); */
+
+ if(ok) {
+ efa= fillfacebase.first;
+ while(efa) {
+ addfacelist(efa->v1->vn, efa->v2->vn, efa->v3->vn, 0, efa);
+ efa= efa->next;
+ }
+ }
+ /* else printf("fill error\n"); */
+
+ BLI_end_edgefill();
+
+ waitcursor(0);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+
+
+/* ******************** SUBDIVIDE ********************************** */
+
+
+static unsigned int cpack_fact(unsigned int col1, unsigned int col2, float fact)
+{
+ char *cp1, *cp2, *cp;
+ unsigned int col=0;
+ float fact1;
+
+ fact1=1-fact; /*result is fact% col1 and (1-fact) % col2 */
+
+ cp1= (char *)&col1;
+ cp2= (char *)&col2;
+ cp= (char *)&col;
+
+ cp[0]= fact*cp1[0]+fact1*cp2[0];
+ cp[1]= fact*cp1[1]+fact1*cp2[1];
+ cp[2]= fact*cp1[2]+fact1*cp2[2];
+ cp[3]= fact*cp1[3]+fact1*cp2[3];
+
+ return col;
+}
+
+
+static void uv_half(float *uv, float *uv1, float *uv2)
+{
+ uv[0]= (uv1[0]+uv2[0])/2.0;
+ uv[1]= (uv1[1]+uv2[1])/2.0;
+
+}
+
+static void uv_quart(float *uv, float *uv1)
+{
+ uv[0]= (uv1[0]+uv1[2]+uv1[4]+uv1[6])/4.0;
+ uv[1]= (uv1[1]+uv1[3]+uv1[5]+uv1[7])/4.0;
+}
+
+static void face_pin_vertex(EditFace *efa, EditVert *vertex)
+{
+ if(efa->v1 == vertex) efa->tf.unwrap |= TF_PIN1;
+ else if(efa->v2 == vertex) efa->tf.unwrap |= TF_PIN2;
+ else if(efa->v3 == vertex) efa->tf.unwrap |= TF_PIN3;
+ else if(efa->v4 && vertex && efa->v4 == vertex) efa->tf.unwrap |= TF_PIN4;
+}
+
+static void set_wuv(int tot, EditFace *efa, int v1, int v2, int v3, int v4, EditFace *efapin)
+{
+ /* this weird function only to be used for subdivide, the 'w' in the name has no meaning! */
+ float *uv, uvo[4][2];
+ unsigned int *col, colo[4], col1, col2;
+ int a, v;
+
+ /* recover pinning */
+ if(efapin){
+ efa->tf.unwrap= 0;
+ if(efapin->tf.unwrap & TF_PIN1) face_pin_vertex(efa, efapin->v1);
+ if(efapin->tf.unwrap & TF_PIN2) face_pin_vertex(efa, efapin->v2);
+ if(efapin->tf.unwrap & TF_PIN3) face_pin_vertex(efa, efapin->v3);
+ if(efapin->tf.unwrap & TF_PIN4) face_pin_vertex(efa, efapin->v4);
+ }
+
+ /* Numbers corespond to verts (corner points), */
+ /* edge->vn's (center edges), the Center */
+ memcpy(uvo, efa->tf.uv, sizeof(uvo)); /* And the quincunx points of a face */
+ uv= efa->tf.uv[0]; /* as shown here: */
+ /* 2 5 1 */
+ memcpy(colo, efa->tf.col, sizeof(colo)); /* 10 13 */
+ col= efa->tf.col; /* 6 9 8 */
+ /* 11 12 */
+ if(tot==4) { /* 3 7 4 */
+ for(a=0; a<4; a++, uv+=2, col++) {
+ if(a==0) v= v1;
+ else if(a==1) v= v2;
+ else if(a==2) v= v3;
+ else v= v4;
+
+ if(a==3 && v4==0) break;
+
+ if(v<=4) {
+ uv[0]= uvo[v-1][0];
+ uv[1]= uvo[v-1][1];
+ *col= colo[v-1];
+ }
+ else if(v==8) {
+ uv_half(uv, uvo[3], uvo[0]);
+ *col= cpack_fact(colo[3], colo[0], 0.5);
+ }
+ else if(v==9) {
+ uv_quart(uv, uvo[0]);
+ col1= cpack_fact(colo[1], colo[0], 0.5);
+ col2= cpack_fact(colo[2], colo[3], 0.5);
+ *col= cpack_fact(col1, col2, 0.5);
+ }
+ /* Cases for adjacent edge square subdivide Real voodoo */
+ /* 1/2 closest corner + 1/4 adjacent corners */
+ else if (v==10){ /* case test==3 in subdivideflag() */
+ uv[0]=(2*uvo[1][0]+uvo[0][0]+uvo[2][0])/4;
+ uv[1]=(2*uvo[1][1]+uvo[0][1]+uvo[2][1])/4;
+ col1= cpack_fact(colo[1], colo[0], 0.75);
+ col2= cpack_fact(colo[2], colo[3], 0.75);
+ *col= cpack_fact(col1, col2, 0.75);
+ }
+ else if (v==11) { /* case of test==6 */
+ uv[0]=(2*uvo[2][0]+uvo[1][0]+uvo[3][0])/4;
+ uv[1]=(2*uvo[2][1]+uvo[1][1]+uvo[3][1])/4;
+ col1= cpack_fact(colo[1], colo[0], 0.75);
+ col2= cpack_fact(colo[2], colo[3], 0.75);
+ *col= cpack_fact(col1, col2, 0.25);
+ }
+ else if (v==12) { /* case of test==12 */
+ uv[0]=(2*uvo[3][0]+uvo[2][0]+uvo[0][0])/4;
+ uv[1]=(2*uvo[3][1]+uvo[2][1]+uvo[0][1])/4;
+ col1= cpack_fact(colo[1], colo[0], 0.25);
+ col2= cpack_fact(colo[2], colo[3], 0.25);
+ *col= cpack_fact(col1, col2, 0.25);
+ }
+ else if (v==13) { /* case of test==9 */
+ uv[0]=(2*uvo[0][0]+uvo[1][0]+uvo[3][0])/4;
+ uv[1]=(2*uvo[0][1]+uvo[1][1]+uvo[3][1])/4;
+ col1= cpack_fact(colo[1], colo[0], 0.25);
+ col2= cpack_fact(colo[2], colo[3], 0.25);
+ *col= cpack_fact(col1, col2, 0.75);
+ }
+ /* default for consecutive verts*/
+ else {
+ uv_half(uv, uvo[v-5], uvo[v-4]);
+ *col= cpack_fact(colo[v-5], colo[v-4], 0.5);
+ }
+ }
+ }
+ else {
+ for(a=0; a<3; a++, uv+=2, col++) {
+ if(a==0) v= v1;
+ else if(a==1) v= v2;
+ else v= v3;
+
+ if(v<=4) {
+ uv[0]= uvo[v-1][0];
+ uv[1]= uvo[v-1][1];
+ *col= colo[v-1];
+ }
+ else if(v==7) {
+ uv_half(uv, uvo[2], uvo[0]);
+ *col= cpack_fact(colo[2], colo[0], 0.5);
+ }
+ else {
+ uv_half(uv, uvo[v-5], uvo[v-4]);
+ *col= cpack_fact(colo[v-5], colo[v-4], 0.5);
+ }
+ }
+ }
+}
+
+static EditVert *vert_from_number(EditFace *efa, int nr)
+{
+ switch(nr) {
+ case 0:
+ return 0;
+ case 1:
+ return efa->v1;
+ case 2:
+ return efa->v2;
+ case 3:
+ return efa->v3;
+ case 4:
+ return efa->v4;
+ case 5:
+ return efa->e1->vn;
+ case 6:
+ return efa->e2->vn;
+ case 7:
+ return efa->e3->vn;
+ case 8:
+ return efa->e4->vn;
+ }
+
+ return NULL;
+}
+
+static void addface_subdiv(EditFace *efa, int val1, int val2, int val3, int val4, EditVert *eve, EditFace *efapin)
+{
+ EditFace *w;
+ EditVert *v1, *v2, *v3, *v4;
+
+ if(val1>=9) v1= eve;
+ else v1= vert_from_number(efa, val1);
+
+ if(val2>=9) v2= eve;
+ else v2= vert_from_number(efa, val2);
+
+ if(val3>=9) v3= eve;
+ else v3= vert_from_number(efa, val3);
+
+ if(val4>=9) v4= eve;
+ else v4= vert_from_number(efa, val4);
+
+ w= addfacelist(v1, v2, v3, v4, efa);
+ if(w) {
+ if(efa->v4) set_wuv(4, w, val1, val2, val3, val4, efapin);
+ else set_wuv(3, w, val1, val2, val3, val4, efapin);
+ }
+}
+
+static float smoothperc= 0.0;
+
+static void smooth_subdiv_vec(float *v1, float *v2, float *n1, float *n2, float *vec)
+{
+ float len, fac, nor[3], nor1[3], nor2[3];
+
+ VecSubf(nor, v1, v2);
+ len= 0.5*Normalise(nor);
+
+ VECCOPY(nor1, n1);
+ VECCOPY(nor2, n2);
+
+ /* cosine angle */
+ fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
+
+ vec[0]= fac*nor1[0];
+ vec[1]= fac*nor1[1];
+ vec[2]= fac*nor1[2];
+
+ /* cosine angle */
+ fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
+
+ vec[0]+= fac*nor2[0];
+ vec[1]+= fac*nor2[1];
+ vec[2]+= fac*nor2[2];
+
+ vec[0]*= smoothperc*len;
+ vec[1]*= smoothperc*len;
+ vec[2]*= smoothperc*len;
+}
+
+static void smooth_subdiv_quad(EditFace *efa, float *vec)
+{
+
+ float nor1[3], nor2[3];
+ float vec1[3], vec2[3];
+ float cent[3];
+
+ /* vlr->e1->vn is new vertex inbetween v1 / v2 */
+
+ VecMidf(nor1, efa->v1->no, efa->v2->no);
+ Normalise(nor1);
+ VecMidf(nor2, efa->v3->no, efa->v4->no);
+ Normalise(nor2);
+
+ smooth_subdiv_vec( efa->e1->vn->co, efa->e3->vn->co, nor1, nor2, vec1);
+
+ VecMidf(nor1, efa->v2->no, efa->v3->no);
+ Normalise(nor1);
+ VecMidf(nor2, efa->v4->no, efa->v1->no);
+ Normalise(nor2);
+
+ smooth_subdiv_vec( efa->e2->vn->co, efa->e4->vn->co, nor1, nor2, vec2);
+
+ VecAddf(vec1, vec1, vec2);
+
+ CalcCent4f(cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+ VecAddf(vec, cent, vec1);
+}
+
+void subdivideflag(int flag, float rad, int beauty)
+{
+ EditMesh *em = G.editMesh;
+ /* subdivide all with (vertflag & flag) */
+ /* if rad>0.0 it's a 'sphere' subdivide */
+ /* if rad<0.0 it's a fractal subdivide */
+ extern float doublimit;
+ EditVert *eve;
+ EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
+ EditFace *efa, efapin;
+ float fac, vec[3], vec1[3], len1, len2, len3, percent;
+ short test;
+
+ if(beauty & B_SMOOTH) {
+ short perc= 100;
+
+ if(button(&perc, 10, 500, "Percentage:")==0) return;
+
+ smoothperc= 0.292*perc/100.0;
+ }
+
+ /* edgeflags */
+ eed= em->edges.first;
+ while((eed) && !(beauty & B_KNIFE)) {
+ if( (eed->v1->f & flag) && (eed->v2->f & flag) ) eed->f= flag;
+ else eed->f= 0;
+ eed= eed->next;
+ }
+
+ /* if beauty: test for area and clear edge flags of 'ugly' edges */
+ if(beauty & B_BEAUTY) {
+ efa= em->faces.first;
+ while(efa) {
+ if( faceselectedAND(efa, flag) ) {
+ if(efa->v4) {
+
+ /* area */
+ len1= AreaQ3Dfl(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+ if(len1 <= doublimit) {
+ efa->e1->f = 0;
+ efa->e2->f = 0;
+ efa->e3->f = 0;
+ efa->e4->f = 0;
+ }
+ else {
+ len1= VecLenf(efa->v1->co, efa->v2->co) + VecLenf(efa->v3->co, efa->v4->co);
+ len2= VecLenf(efa->v2->co, efa->v3->co) + VecLenf(efa->v1->co, efa->v4->co);
+
+ if(len1 < len2) {
+ efa->e1->f = 0;
+ efa->e3->f = 0;
+ }
+ else if(len1 > len2) {
+ efa->e2->f = 0;
+ efa->e4->f = 0;
+ }
+ }
+ }
+ else {
+ /* area */
+ len1= AreaT3Dfl(efa->v1->co, efa->v2->co, efa->v3->co);
+ if(len1 <= doublimit) {
+ efa->e1->f = 0;
+ efa->e2->f = 0;
+ efa->e3->f = 0;
+ }
+ else {
+ len1= VecLenf(efa->v1->co, efa->v2->co) ;
+ len2= VecLenf(efa->v2->co, efa->v3->co) ;
+ len3= VecLenf(efa->v3->co, efa->v1->co) ;
+
+ if(len1<len2 && len1<len3) {
+ efa->e1->f = 0;
+ }
+ else if(len2<len3 && len2<len1) {
+ efa->e2->f = 0;
+ }
+ else if(len3<len2 && len3<len1) {
+ efa->e3->f = 0;
+ }
+ }
+ }
+ }
+ efa= efa->next;
+ }
+ }
+
+ if(beauty & B_SMOOTH) {
+
+ vertexnormals(0); /* no1*/
+
+ }
+
+ /* make new normal and put in edge, clear flag! needed for face creation part below */
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->f & flag) {
+ /* Subdivide percentage is stored in 1/32768ths in eed->f1 */
+ if (beauty & B_PERCENTSUBD) percent=(float)(eed->f1)/32768.0;
+ else percent=0.5;
+
+ vec[0]= (1-percent)*eed->v1->co[0] + percent*eed->v2->co[0];
+ vec[1]= (1-percent)*eed->v1->co[1] + percent*eed->v2->co[1];
+ vec[2]= (1-percent)*eed->v1->co[2] + percent*eed->v2->co[2];
+
+ if(rad > 0.0) { /* subdivide sphere */
+ Normalise(vec);
+ vec[0]*= rad;
+ vec[1]*= rad;
+ vec[2]*= rad;
+ }
+ else if(rad< 0.0) { /* fractal subdivide */
+ fac= rad* VecLenf(eed->v1->co, eed->v2->co);
+ vec1[0]= fac*BLI_drand();
+ vec1[1]= fac*BLI_drand();
+ vec1[2]= fac*BLI_drand();
+ VecAddf(vec, vec, vec1);
+ }
+
+ if(beauty & B_SMOOTH) {
+ smooth_subdiv_vec(eed->v1->co, eed->v2->co, eed->v1->no, eed->v2->no, vec1);
+ VecAddf(vec, vec, vec1);
+ }
+
+ eed->vn= addvertlist(vec);
+ eed->vn->f= eed->v1->f;
+
+ }
+ else eed->vn= 0;
+
+ eed->f= 0; /* needed! */
+
+ eed= eed->next;
+ }
+
+ /* test all faces for subdivide edges, there are 8 or 16 cases (ugh)! */
+
+ efa= em->faces.last;
+ while(efa) {
+
+ efapin= *efa; /* make a copy of efa to recover uv pinning later */
+
+ if( faceselectedOR(efa, flag) ) {
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ e4= efa->e4;
+
+ test= 0;
+ if(e1 && e1->vn) {
+ test+= 1;
+ e1->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e1->v1, e1->vn, e1);
+ eed= addedgelist(e1->vn, e1->v2, e1);
+ }
+ if(e2 && e2->vn) {
+ test+= 2;
+ e2->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e2->v1, e2->vn, e2);
+ eed= addedgelist(e2->vn, e2->v2, e2);
+ }
+ if(e3 && e3->vn) {
+ test+= 4;
+ e3->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e3->v1, e3->vn, e3);
+ eed= addedgelist(e3->vn, e3->v2, e3);
+ }
+ if(e4 && e4->vn) {
+ test+= 8;
+ e4->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e4->v1, e4->vn, e4);
+ eed= addedgelist(e4->vn, e4->v2, e4);
+ }
+ if(test) {
+ if(efa->v4==0) { /* All the permutations of 3 edges*/
+ if((test & 3)==3) addface_subdiv(efa, 2, 2+4, 1+4, 0, 0, &efapin);
+ if((test & 6)==6) addface_subdiv(efa, 3, 3+4, 2+4, 0, 0, &efapin);
+ if((test & 5)==5) addface_subdiv(efa, 1, 1+4, 3+4, 0, 0, &efapin);
+
+ if(test==7) { /* four new faces, old face renews */
+ efa->v1= e1->vn;
+ efa->v2= e2->vn;
+ efa->v3= e3->vn;
+ set_wuv(3, efa, 1+4, 2+4, 3+4, 0, &efapin);
+ }
+ else if(test==3) {
+ addface_subdiv(efa, 1+4, 2+4, 3, 0, 0, &efapin);
+ efa->v2= e1->vn;
+ set_wuv(3, efa, 1, 1+4, 3, 0, &efapin);
+ }
+ else if(test==6) {
+ addface_subdiv(efa, 2+4, 3+4, 1, 0, 0, &efapin);
+ efa->v3= e2->vn;
+ set_wuv(3, efa, 1, 2, 2+4, 0, &efapin);
+ }
+ else if(test==5) {
+ addface_subdiv(efa, 3+4, 1+4, 2, 0, 0, &efapin);
+ efa->v1= e3->vn;
+ set_wuv(3, efa, 3+4, 2, 3, 0, &efapin);
+ }
+ else if(test==1) {
+ addface_subdiv(efa, 1+4, 2, 3, 0, 0, &efapin);
+ efa->v2= e1->vn;
+ set_wuv(3, efa, 1, 1+4, 3, 0, &efapin);
+ }
+ else if(test==2) {
+ addface_subdiv(efa, 2+4, 3, 1, 0, 0, &efapin);
+ efa->v3= e2->vn;
+ set_wuv(3, efa, 1, 2, 2+4, 0, &efapin);
+ }
+ else if(test==4) {
+ addface_subdiv(efa, 3+4, 1, 2, 0, 0, &efapin);
+ efa->v1= e3->vn;
+ set_wuv(3, efa, 3+4, 2, 3, 0, &efapin);
+ }
+ efa->e1= addedgelist(efa->v1, efa->v2, NULL);
+ efa->e2= addedgelist(efa->v2, efa->v3, NULL);
+ efa->e3= addedgelist(efa->v3, efa->v1, NULL);
+
+ }
+ else { /* All the permutations of 4 faces */
+ if(test==15) {
+ /* add a new point in center */
+ CalcCent4f(vec, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+
+ if(beauty & B_SMOOTH) {
+ smooth_subdiv_quad(efa, vec); /* adds */
+ }
+ eve= addvertlist(vec);
+
+ eve->f |= flag;
+
+ addface_subdiv(efa, 2, 2+4, 9, 1+4, eve, &efapin);
+ addface_subdiv(efa, 3, 3+4, 9, 2+4, eve, &efapin);
+ addface_subdiv(efa, 4, 4+4, 9, 3+4, eve, &efapin);
+
+ efa->v2= e1->vn;
+ efa->v3= eve;
+ efa->v4= e4->vn;
+ set_wuv(4, efa, 1, 1+4, 9, 4+4, &efapin);
+ }
+ else {
+ if(((test & 3)==3)&&(test!=3)) addface_subdiv(efa, 1+4, 2, 2+4, 0, 0, &efapin);
+ if(((test & 6)==6)&&(test!=6)) addface_subdiv(efa, 2+4, 3, 3+4, 0, 0, &efapin);
+ if(((test & 12)==12)&&(test!=12)) addface_subdiv(efa, 3+4, 4, 4+4, 0, 0, &efapin);
+ if(((test & 9)==9)&&(test!=9)) addface_subdiv(efa, 4+4, 1, 1+4, 0, 0, &efapin);
+
+ if(test==1) { /* Edge 1 has new vert */
+ addface_subdiv(efa, 1+4, 2, 3, 0, 0, &efapin);
+ addface_subdiv(efa, 1+4, 3, 4, 0, 0, &efapin);
+ efa->v2= e1->vn;
+ efa->v3= efa->v4;
+ efa->v4= 0;
+ set_wuv(4, efa, 1, 1+4, 4, 0, &efapin);
+ }
+ else if(test==2) { /* Edge 2 has new vert */
+ addface_subdiv(efa, 2+4, 3, 4, 0, 0, &efapin);
+ addface_subdiv(efa, 2+4, 4, 1, 0, 0, &efapin);
+ efa->v3= e2->vn;
+ efa->v4= 0;
+ set_wuv(4, efa, 1, 2, 2+4, 0, &efapin);
+ }
+ else if(test==4) { /* Edge 3 has new vert */
+ addface_subdiv(efa, 3+4, 4, 1, 0, 0, &efapin);
+ addface_subdiv(efa, 3+4, 1, 2, 0, 0, &efapin);
+ efa->v1= efa->v2;
+ efa->v2= efa->v3;
+ efa->v3= e3->vn;
+ efa->v4= 0;
+ set_wuv(4, efa, 2, 3, 3+4, 0, &efapin);
+ }
+ else if(test==8) { /* Edge 4 has new vert */
+ addface_subdiv(efa, 4+4, 1, 2, 0, 0, &efapin);
+ addface_subdiv(efa, 4+4, 2, 3, 0, 0, &efapin);
+ efa->v1= efa->v3;
+ efa->v2= efa->v4;
+ efa->v3= e4->vn;
+ efa->v4= 0;
+ set_wuv(4, efa, 3, 4, 4+4, 0, &efapin);
+ }
+ else if(test==3) { /*edge 1&2 */
+ /* make new vert in center of new edge */
+ vec[0]=(e1->vn->co[0]+e2->vn->co[0])/2;
+ vec[1]=(e1->vn->co[1]+e2->vn->co[1])/2;
+ vec[2]=(e1->vn->co[2]+e2->vn->co[2])/2;
+ eve= addvertlist(vec);
+ eve->f |= flag;
+ /* Add new faces */
+ addface_subdiv(efa, 4, 10, 2+4, 3, eve, &efapin);
+ addface_subdiv(efa, 4, 1, 1+4, 10, eve, &efapin);
+ /* orig face becomes small corner */
+ efa->v1=e1->vn;
+ //efa->v2=efa->v2;
+ efa->v3=e2->vn;
+ efa->v4=eve;
+
+ set_wuv(4, efa, 1+4, 2, 2+4, 10, &efapin);
+ }
+ else if(test==6) { /* 2&3 */
+ /* make new vert in center of new edge */
+ vec[0]=(e2->vn->co[0]+e3->vn->co[0])/2;
+ vec[1]=(e2->vn->co[1]+e3->vn->co[1])/2;
+ vec[2]=(e2->vn->co[2]+e3->vn->co[2])/2;
+ eve= addvertlist(vec);
+ eve->f |= flag;
+ /*New faces*/
+ addface_subdiv(efa, 1, 11, 3+4, 4, eve, &efapin);
+ addface_subdiv(efa, 1, 2, 2+4, 11, eve, &efapin);
+ /* orig face becomes small corner */
+ efa->v1=e2->vn;
+ efa->v2=efa->v3;
+ efa->v3=e3->vn;
+ efa->v4=eve;
+
+ set_wuv(4, efa, 2+4, 3, 3+4, 11, &efapin);
+ }
+ else if(test==12) { /* 3&4 */
+ /* make new vert in center of new edge */
+ vec[0]=(e3->vn->co[0]+e4->vn->co[0])/2;
+ vec[1]=(e3->vn->co[1]+e4->vn->co[1])/2;
+ vec[2]=(e3->vn->co[2]+e4->vn->co[2])/2;
+ eve= addvertlist(vec);
+ eve->f |= flag;
+ /*New Faces*/
+ addface_subdiv(efa, 2, 12, 4+4, 1, eve, &efapin);
+ addface_subdiv(efa, 2, 3, 3+4, 12, eve, &efapin);
+ /* orig face becomes small corner */
+ efa->v1=e3->vn;
+ efa->v2=efa->v4;
+ efa->v3=e4->vn;
+ efa->v4=eve;
+
+ set_wuv(4, efa, 3+4, 4, 4+4, 12, &efapin);
+ }
+ else if(test==9) { /* 4&1 */
+ /* make new vert in center of new edge */
+ vec[0]=(e1->vn->co[0]+e4->vn->co[0])/2;
+ vec[1]=(e1->vn->co[1]+e4->vn->co[1])/2;
+ vec[2]=(e1->vn->co[2]+e4->vn->co[2])/2;
+ eve= addvertlist(vec);
+ eve->f |= flag;
+ /*New Faces*/
+ addface_subdiv(efa, 3, 13, 1+4, 2, eve, &efapin);
+ addface_subdiv(efa, 3, 4, 4+4,13, eve, &efapin);
+ /* orig face becomes small corner */
+ efa->v2=efa->v1;
+ efa->v1=e4->vn;
+ efa->v3=e1->vn;
+ efa->v4=eve;
+
+ set_wuv(4, efa, 4+4, 1, 1+4, 13, &efapin);
+ }
+ else if(test==5) { /* 1&3 */
+ addface_subdiv(efa, 1+4, 2, 3, 3+4, 0, &efapin);
+ efa->v2= e1->vn;
+ efa->v3= e3->vn;
+ set_wuv(4, efa, 1, 1+4, 3+4, 4, &efapin);
+ }
+ else if(test==10) { /* 2&4 */
+ addface_subdiv(efa, 2+4, 3, 4, 4+4, 0, &efapin);
+ efa->v3= e2->vn;
+ efa->v4= e4->vn;
+ set_wuv(4, efa, 1, 2, 2+4, 4+4, &efapin);
+ }/* Unfortunately, there is no way to avoid tris on 1 or 3 edges*/
+ else if(test==7) { /*1,2&3 */
+ addface_subdiv(efa, 1+4, 2+4, 3+4, 0, 0, &efapin);
+ efa->v2= e1->vn;
+ efa->v3= e3->vn;
+ set_wuv(4, efa, 1, 1+4, 3+4, 4, &efapin);
+ }
+
+ else if(test==14) { /* 2,3&4 */
+ addface_subdiv(efa, 2+4, 3+4, 4+4, 0, 0, &efapin);
+ efa->v3= e2->vn;
+ efa->v4= e4->vn;
+ set_wuv(4, efa, 1, 2, 2+4, 4+4, &efapin);
+ }
+ else if(test==13) {/* 1,3&4 */
+ addface_subdiv(efa, 3+4, 4+4, 1+4, 0, 0, &efapin);
+ efa->v4= e3->vn;
+ efa->v1= e1->vn;
+ set_wuv(4, efa, 1+4, 3, 3, 3+4, &efapin);
+ }
+ else if(test==11) { /* 1,2,&4 */
+ addface_subdiv(efa, 4+4, 1+4, 2+4, 0, 0, &efapin);
+ efa->v1= e4->vn;
+ efa->v2= e2->vn;
+ set_wuv(4, efa, 4+4, 2+4, 3, 4, &efapin);
+ }
+ }
+ efa->e1= addedgelist(efa->v1, efa->v2, NULL);
+ efa->e2= addedgelist(efa->v2, efa->v3, NULL);
+ if(efa->v4) efa->e3= addedgelist(efa->v3, efa->v4, NULL);
+ else efa->e3= addedgelist(efa->v3, efa->v1, NULL);
+ if(efa->v4) efa->e4= addedgelist(efa->v4, efa->v1, NULL);
+ else efa->e4= NULL;
+ }
+ }
+ }
+ efa= efa->prev;
+ }
+
+ /* remove all old edges, if needed make new ones */
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if( eed->vn ) {
+ eed->vn->f |= 16;
+ if(eed->f==0) { /* not used in face */
+ addedgelist(eed->v1, eed->vn, eed);
+ addedgelist(eed->vn, eed->v2, eed);
+ }
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+static int count_edges(EditEdge *ed)
+{
+ int totedge = 0;
+ while(ed) {
+ ed->vn= 0;
+ if( (ed->v1->f & 1) && (ed->v2->f & 1) ) 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->f) */
+
+static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
+{
+ int i = 0;
+ EditEdge *e1, *e2, *e3;
+ EVPtr *evp;
+
+ /* run through edges, if selected, set pointer edge-> facearray */
+ while(eed) {
+ eed->f= 0;
+ eed->f1= 0;
+ if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
+ eed->vn= (EditVert *) (&efaa[i]);
+ i++;
+ }
+ eed= eed->next;
+ }
+
+
+ /* find edges pointing to 2 faces by procedure:
+
+ - run through faces and their edges, increase
+ face counter e->f for each face
+ */
+
+ while(efa) {
+ efa->f1= 0;
+ if(efa->v4==0) { /* if triangle */
+ if(faceselectedAND(efa, 1)) {
+
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ if(e1->f<3) {
+ if(e1->f<2) {
+ evp= (EVPtr *) e1->vn;
+ evp[(int)e1->f]= efa;
+ }
+ e1->f+= 1;
+ }
+ if(e2->f<3) {
+ if(e2->f<2) {
+ evp= (EVPtr *) e2->vn;
+ evp[(int)e2->f]= efa;
+ }
+ e2->f+= 1;
+ }
+ if(e3->f<3) {
+ if(e3->f<2) {
+ evp= (EVPtr *) e3->vn;
+ evp[(int)e3->f]= efa;
+ }
+ e3->f+= 1;
+ }
+ }
+ }
+ 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, float **uv, unsigned int *col)
+{
+ if VTEST(efa, 1, efa1) {
+ //if(efa->v1!=efa1->v1 && efa->v1!=efa1->v2 && efa->v1!=efa1->v3) {
+ *v1= efa->v1;
+ *v2= efa->v2;
+ uv[0] = efa->tf.uv[0];
+ uv[1] = efa->tf.uv[1];
+ col[0] = efa->tf.col[0];
+ col[1] = efa->tf.col[1];
+ }
+ else if VTEST(efa, 2, efa1) {
+ //else if(efa->v2!=efa1->v1 && efa->v2!=efa1->v2 && efa->v2!=efa1->v3) {
+ *v1= efa->v2;
+ *v2= efa->v3;
+ uv[0] = efa->tf.uv[1];
+ uv[1] = efa->tf.uv[2];
+ col[0] = efa->tf.col[1];
+ col[1] = efa->tf.col[2];
+ }
+ else if VTEST(efa, 3, efa1) {
+ // else if(efa->v3!=efa1->v1 && efa->v3!=efa1->v2 && efa->v3!=efa1->v3) {
+ *v1= efa->v3;
+ *v2= efa->v1;
+ uv[0] = efa->tf.uv[2];
+ uv[1] = efa->tf.uv[0];
+ col[0] = efa->tf.col[2];
+ col[1] = efa->tf.col[0];
+ }
+
+ if VTEST(efa1, 1, efa) {
+ // if(efa1->v1!=efa->v1 && efa1->v1!=efa->v2 && efa1->v1!=efa->v3) {
+ *v3= efa1->v1;
+ uv[2] = efa1->tf.uv[0];
+ col[2] = efa1->tf.col[0];
+
+ *v4= efa1->v2;
+ uv[3] = efa1->tf.uv[1];
+ col[3] = efa1->tf.col[1];
+/*
+if(efa1->v2== *v2) {
+ *v4= efa1->v3;
+ uv[3] = efa1->tf.uv[2];
+ } else {
+ *v4= efa1->v2;
+ uv[3] = efa1->tf.uv[1];
+ }
+ */
+ }
+ else if VTEST(efa1, 2, efa) {
+ // else if(efa1->v2!=efa->v1 && efa1->v2!=efa->v2 && efa1->v2!=efa->v3) {
+ *v3= efa1->v2;
+ uv[2] = efa1->tf.uv[1];
+ col[2] = efa1->tf.col[1];
+
+ *v4= efa1->v3;
+ uv[3] = efa1->tf.uv[2];
+ col[3] = efa1->tf.col[2];
+/*
+if(efa1->v3== *v2) {
+ *v4= efa1->v1;
+ uv[3] = efa1->tf.uv[0];
+ } else {
+ *v4= efa1->v3;
+ uv[3] = efa1->tf.uv[2];
+ }
+ */
+ }
+ else if VTEST(efa1, 3, efa) {
+ // else if(efa1->v3!=efa->v1 && efa1->v3!=efa->v2 && efa1->v3!=efa->v3) {
+ *v3= efa1->v3;
+ uv[2] = efa1->tf.uv[2];
+ col[2] = efa1->tf.col[2];
+
+ *v4= efa1->v1;
+ uv[3] = efa1->tf.uv[0];
+ col[3] = efa1->tf.col[0];
+/*
+if(efa1->v1== *v2) {
+ *v4= efa1->v2;
+ uv[3] = efa1->tf.uv[3];
+ } else {
+ *v4= efa1->v1;
+ uv[3] = efa1->tf.uv[0];
+ }
+ */
+ }
+ else {
+ printf("error in givequadverts()\n");
+ return;
+ }
+
+}
+
+/* Helper functions for edge/quad edit features*/
+
+static void untag_edges(EditFace *f)
+{
+ f->e1->f = 0;
+ f->e2->f = 0;
+ if (f->e3) f->e3->f = 0;
+ if (f->e4) f->e4->f = 0;
+}
+
+/** remove and free list of tagged edges */
+static void free_tagged_edgelist(EditEdge *eed)
+{
+ EditEdge *nexted;
+
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f1) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+}
+/** remove and free list of tagged faces */
+
+static void free_tagged_facelist(EditFace *efa)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *nextvl;
+
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f1) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+}
+
+
+void beauty_fill(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1, *v2, *v3, *v4;
+ EditEdge *eed, *nexted;
+ EditEdge dia1, dia2;
+ EditFace *efa, *w;
+ // void **efaar, **efaa;
+ EVPTuple *efaar;
+ EVPtr *efaa;
+ float *uv[4];
+ unsigned int col[4];
+ float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
+ int totedge, ok, notbeauty=8, onedone;
+
+ /* - 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
+ */
+
+ totedge = count_edges(em->edges.first);
+ if(totedge==0) return;
+
+ if(okee("Beautify fill")==0) return;
+
+ undo_push_mesh("Beauty Fill");
+
+ /* 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;
+
+ if(eed->f==2) {
+
+ efaa = (EVPtr *) eed->vn;
+
+ /* none of the faces should be treated before */
+ 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, uv, col);
+ if( convex(v1->co, v2->co, v3->co, v4->co) > -0.5) {
+
+ /* test edges */
+ if( ((long)v1) > ((long)v3) ) {
+ dia1.v1= v3;
+ dia1.v2= v1;
+ }
+ else {
+ dia1.v1= v1;
+ dia1.v2= v3;
+ }
+
+ if( ((long)v2) > ((long)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= VecLenf(v1->co, v2->co);
+ len2= VecLenf(v2->co, v3->co);
+ len3= VecLenf(v3->co, v4->co);
+ len4= VecLenf(v4->co, v1->co);
+ len5= VecLenf(v1->co, v3->co);
+ len6= VecLenf(v2->co, v4->co);
+
+ opp1= AreaT3Dfl(v1->co, v2->co, v3->co);
+ opp2= AreaT3Dfl(v1->co, v3->co, v4->co);
+
+ fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
+
+ opp1= AreaT3Dfl(v2->co, v3->co, v4->co);
+ opp2= AreaT3Dfl(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= addfacelist(v1, v2, v3, 0, efa);
+
+ UVCOPY(w->tf.uv[0], uv[0]);
+ UVCOPY(w->tf.uv[1], uv[1]);
+ UVCOPY(w->tf.uv[2], uv[2]);
+
+ w->tf.col[0] = col[0]; w->tf.col[1] = col[1]; w->tf.col[2] = col[2];
+ w= addfacelist(v1, v3, v4, 0, efa);
+
+ UVCOPY(w->tf.uv[0], uv[0]);
+ UVCOPY(w->tf.uv[1], uv[2]);
+ UVCOPY(w->tf.uv[2], uv[3]);
+
+ w->tf.col[0] = col[0]; w->tf.col[1] = col[2]; w->tf.col[2] = col[3];
+
+ 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= addfacelist(v2, v3, v4, 0, efa);
+
+ UVCOPY(w->tf.uv[0], uv[1]);
+ UVCOPY(w->tf.uv[1], uv[3]);
+ UVCOPY(w->tf.uv[2], uv[4]);
+
+ w= addfacelist(v1, v2, v4, 0, efa);
+
+ UVCOPY(w->tf.uv[0], uv[0]);
+ UVCOPY(w->tf.uv[1], uv[1]);
+ UVCOPY(w->tf.uv[2], uv[3]);
+
+ onedone= 1;
+ }
+ }
+ }
+ }
+
+ }
+ eed= nexted;
+ }
+
+ free_tagged_edgelist(em->edges.first);
+ free_tagged_facelist(em->faces.first);
+
+ if(onedone==0) break;
+ }
+
+ MEM_freeN(efaar);
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+
+/* ******************** FLIP EDGE ************************************* */
+
+
+#define FACE_MARKCLEAR(f) (f->f1 = 1)
+
+void join_triangles(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1, *v2, *v3, *v4;
+ EditFace *efa, *w;
+ EVPTuple *efaar;
+ EVPtr *efaa;
+ EditEdge *eed, *nexted;
+ int totedge, ok;
+ float *uv[4];
+ unsigned int col[4];
+
+
+ totedge = count_edges(em->edges.first);
+ if(totedge==0) return;
+
+ undo_push_mesh("Convert Triangles to Quads");
+
+ efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "jointris");
+
+ ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
+ if (G.f & G_DEBUG) {
+ printf("Edges selected: %d\n", ok);
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+
+ if(eed->f==2) { /* points to 2 faces */
+
+ efaa= (EVPtr *) eed->vn;
+
+ /* 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, uv, col);
+
+/*
+ 4-----3 4-----3
+ |\ | | |
+ | \ 1 | | |
+ | \ | -> | |
+ | 0 \ | | |
+ | \| | |
+ 1-----2 1-----2
+*/
+ /* make new faces */
+ if( convex(v1->co, v2->co, v3->co, v4->co) > 0.01) {
+ if(exist_face(v1, v2, v3, v4)==0) {
+ w = addfacelist(v1, v2, v3, v4, efaa[0]);
+ untag_edges(w);
+
+ UVCOPY(w->tf.uv[0], uv[0]);
+ UVCOPY(w->tf.uv[1], uv[1]);
+ UVCOPY(w->tf.uv[2], uv[2]);
+ UVCOPY(w->tf.uv[3], uv[3]);
+
+ memcpy(w->tf.col, col, sizeof(w->tf.col));
+ }
+ /* tag as to-be-removed */
+ FACE_MARKCLEAR(efaa[0]);
+ FACE_MARKCLEAR(efaa[1]);
+ eed->f1 = 1;
+ } /* endif test convex */
+ }
+ }
+ eed= nexted;
+ }
+ free_tagged_edgelist(em->edges.first);
+ free_tagged_facelist(em->faces.first);
+
+ MEM_freeN(efaar);
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+
+}
+
+/* quick hack, basically a copy of beauty_fill */
+void edge_flip(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1, *v2, *v3, *v4;
+ EditEdge *eed, *nexted;
+ EditFace *efa, *w;
+ //void **efaar, **efaa;
+ EVPTuple *efaar;
+ EVPtr *efaa;
+
+ float *uv[4];
+ unsigned int col[4];
+
+ int totedge, ok;
+
+ /* - 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
+ */
+
+ totedge = count_edges(em->edges.first);
+ if(totedge==0) return;
+
+ undo_push_mesh("Flip Triangle Edges");
+
+ /* 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->f==2) { /* points to 2 faces */
+
+ efaa= (EVPtr *) eed->vn;
+
+ /* 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, uv, col);
+
+/*
+ 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) > 0.01) {
+ if(exist_face(v1, v2, v3, v4)==0) {
+ w = addfacelist(v1, v2, v3, 0, efaa[1]);
+
+ untag_edges(w);
+
+ UVCOPY(w->tf.uv[0], uv[0]);
+ UVCOPY(w->tf.uv[1], uv[1]);
+ UVCOPY(w->tf.uv[2], uv[2]);
+
+ w->tf.col[0] = col[0]; w->tf.col[1] = col[1]; w->tf.col[2] = col[2];
+
+ w = addfacelist(v1, v3, v4, 0, efaa[1]);
+ untag_edges(w);
+
+ UVCOPY(w->tf.uv[0], uv[0]);
+ UVCOPY(w->tf.uv[1], uv[2]);
+ UVCOPY(w->tf.uv[2], uv[3]);
+
+ w->tf.col[0] = col[0]; w->tf.col[1] = col[2]; w->tf.col[2] = col[3];
+
+ /* erase old faces and edge */
+ }
+ /* 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_edgelist(em->edges.first);
+ free_tagged_facelist(em->faces.first);
+
+ MEM_freeN(efaar);
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+static void edge_rotate(EditEdge *eed){
+ EditMesh *em = G.editMesh;
+ EditFace *face[2], *efa, *newFace[2];
+ EditVert *faces[2][4],*v1,*v2,*v3,*v4,*vtemp;
+ short facecount=0, p1=0,p2=0,p3=0,p4=0,fac1=4,fac2=4,i,j;
+
+ /* check to make sure that the edge is only part of 2 faces */
+ 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){
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ return;
+ }
+ if(facecount < 2)
+ face[facecount] = efa;
+ facecount++;
+ }
+ }
+
+
+ if(facecount < 2){
+ return;
+ }
+
+
+ /* how many edges does each face have */
+ if(face[0]->e4 == NULL)
+ fac1=3;
+ else
+ fac1=4;
+ if(face[1]->e4 == NULL)
+ fac2=3;
+ else
+ fac2=4;
+
+
+ /*store the face info in a handy array */
+ faces[0][0] = face[0]->v1;
+ faces[0][1] = face[0]->v2;
+ faces[0][2] = face[0]->v3;
+ if(face[0]->e4 != NULL)
+ faces[0][3] = face[0]->v4;
+ else
+ faces[0][3] = NULL;
+
+ faces[1][0] = face[1]->v1;
+ faces[1][1] = face[1]->v2;
+ faces[1][2] = face[1]->v3;
+ if(face[1]->e4 != NULL)
+ faces[1][3] = face[1]->v4;
+ else
+ faces[1][3] = NULL;
+
+
+ /* we don't want to rotate edges between faces that share more than one edge */
+
+ j=0;
+ if(face[0]->e1 == face[1]->e1 ||
+ face[0]->e1 == face[1]->e2 ||
+ face[0]->e1 == face[1]->e3 ||
+ ((face[1]->e4) && face[0]->e1 == face[1]->e4) )
+ j++;
+
+ if(face[0]->e2 == face[1]->e1 ||
+ face[0]->e2 == face[1]->e2 ||
+ face[0]->e2 == face[1]->e3 ||
+ ((face[1]->e4) && face[0]->e2 == face[1]->e4) )
+ j++;
+
+ if(face[0]->e3 == face[1]->e1 ||
+ face[0]->e3 == face[1]->e2 ||
+ face[0]->e3 == face[1]->e3 ||
+ ((face[1]->e4) && face[0]->e3 == face[1]->e4) )
+ j++;
+
+ if(face[0]->e4){
+ if(face[0]->e4 == face[1]->e1 ||
+ face[0]->e4 == face[1]->e2 ||
+ face[0]->e4 == face[1]->e3 ||
+ ((face[1]->e4) && face[0]->e4 == face[1]->e4) )
+ j++;
+ }
+ if(j > 1){
+ return;
+ }
+
+ /* Coplaner Faces Only Please */
+ if(Inpf(face[0]->n,face[1]->n) <= 0.000001){
+ return;
+ }
+
+ /*get the edges verts */
+ v1 = eed->v1;
+ v2 = eed->v2;
+ v3 = eed->v1;
+ v4 = eed->v2;
+
+
+ /*figure out where the edges verts lie one the 2 faces */
+ for(i=0;i<4;i++){
+ if(v1 == faces[0][i])
+ p1 = i;
+ if(v2 == faces[0][i])
+ p2 = i;
+ if(v1 == faces[1][i])
+ p3 = i;
+ if(v2 == faces[1][i])
+ p4 = i;
+ }
+
+ /*make sure the verts are in the correct order */
+ if((p1+1)%fac1 == p2){
+ vtemp = v2;
+ v2 = v1;
+ v1 = vtemp;
+
+ i = p1;
+ p1 = p2;
+ p2 = i;
+ }
+ if((p3+1)%fac2 == p4){
+ vtemp = v4;
+ v4 = v3;
+ v3 = vtemp;
+
+ i = p3;
+ p3 = p4;
+ p4 = i;
+ }
+
+
+
+ /* create the 2 new faces */
+ if(fac1 == 3 && fac2 == 3){
+ newFace[0] = addfacelist(faces[0][(p1+1)%3],faces[0][(p1+2)%3],faces[1][(p3+1)%3],NULL,NULL);
+ newFace[1] = addfacelist(faces[1][(p3+1)%3],faces[1][(p3+2)%3],faces[0][(p1+1)%3],NULL,NULL);
+
+ newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%3];
+ newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%3];
+ newFace[0]->tf.col[2] = face[1]->tf.col[(p3+1)%3];
+ newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%3];
+ newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%3];
+ newFace[1]->tf.col[2] = face[0]->tf.col[(p1+1)%3];
+
+ UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%3]);
+ UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%3]);
+ UVCOPY(newFace[0]->tf.uv[2],face[1]->tf.uv[(p3+1)%3]);
+ UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%3]);
+ UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%3]);
+ UVCOPY(newFace[1]->tf.uv[2],face[0]->tf.uv[(p1+1)%3]);
+ }
+ else if(fac1 == 4 && fac2 == 3){
+ newFace[0] = addfacelist(faces[0][(p1+1)%4],faces[0][(p1+2)%4],faces[0][(p1+3)%4],faces[1][(p3+1)%3],NULL);
+ newFace[1] = addfacelist(faces[1][(p3+1)%3],faces[1][(p3+2)%3],faces[0][(p1+1)%4],NULL,NULL);
+
+ newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%4];
+ newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%4];
+ newFace[0]->tf.col[2] = face[0]->tf.col[(p1+3)%4];
+ newFace[0]->tf.col[3] = face[1]->tf.col[(p3+1)%3];
+ newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%3];
+ newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%3];
+ newFace[1]->tf.col[2] = face[0]->tf.col[(p1+1)%4];
+
+ UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%4]);
+ UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%4]);
+ UVCOPY(newFace[0]->tf.uv[2],face[0]->tf.uv[(p1+3)%4]);
+ UVCOPY(newFace[0]->tf.uv[3],face[1]->tf.uv[(p3+1)%3]);
+ UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%3]);
+ UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%3]);
+ UVCOPY(newFace[1]->tf.uv[2],face[0]->tf.uv[(p1+1)%4]);
+ }
+
+ else if(fac1 == 3 && fac2 == 4){
+ newFace[0] = addfacelist(faces[0][(p1+1)%3],faces[0][(p1+2)%3],faces[1][(p3+1)%4],NULL,NULL);
+ newFace[1] = addfacelist(faces[1][(p3+1)%4],faces[1][(p3+2)%4],faces[1][(p3+3)%4],faces[0][(p1+1)%3],NULL);
+
+ newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%3];
+ newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%3];
+ newFace[0]->tf.col[2] = face[1]->tf.col[(p3+1)%4];
+ newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%4];
+ newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%4];
+ newFace[1]->tf.col[2] = face[1]->tf.col[(p3+3)%4];
+ newFace[1]->tf.col[3] = face[0]->tf.col[(p1+1)%3];
+
+ UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%3]);
+ UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%3]);
+ UVCOPY(newFace[0]->tf.uv[2],face[1]->tf.uv[(p3+1)%4]);
+ UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%4]);
+ UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%4]);
+ UVCOPY(newFace[1]->tf.uv[2],face[1]->tf.uv[(p3+3)%4]);
+ UVCOPY(newFace[1]->tf.uv[3],face[0]->tf.uv[(p1+1)%3]);
+
+ }
+
+ else if(fac1 == 4 && fac2 == 4){
+ newFace[0] = addfacelist(faces[0][(p1+1)%4],faces[0][(p1+2)%4],faces[0][(p1+3)%4],faces[1][(p3+1)%4],NULL);
+ newFace[1] = addfacelist(faces[1][(p3+1)%4],faces[1][(p3+2)%4],faces[1][(p3+3)%4],faces[0][(p1+1)%4],NULL);
+
+ newFace[0]->tf.col[0] = face[0]->tf.col[(p1+1)%4];
+ newFace[0]->tf.col[1] = face[0]->tf.col[(p1+2)%4];
+ newFace[0]->tf.col[2] = face[0]->tf.col[(p1+3)%4];
+ newFace[0]->tf.col[3] = face[1]->tf.col[(p3+1)%4];
+ newFace[1]->tf.col[0] = face[1]->tf.col[(p3+1)%4];
+ newFace[1]->tf.col[1] = face[1]->tf.col[(p3+2)%4];
+ newFace[1]->tf.col[2] = face[1]->tf.col[(p3+3)%4];
+ newFace[1]->tf.col[3] = face[0]->tf.col[(p1+1)%4];
+
+ UVCOPY(newFace[0]->tf.uv[0],face[0]->tf.uv[(p1+1)%4]);
+ UVCOPY(newFace[0]->tf.uv[1],face[0]->tf.uv[(p1+2)%4]);
+ UVCOPY(newFace[0]->tf.uv[2],face[0]->tf.uv[(p1+3)%4]);
+ UVCOPY(newFace[0]->tf.uv[3],face[1]->tf.uv[(p3+1)%4]);
+ UVCOPY(newFace[1]->tf.uv[0],face[1]->tf.uv[(p3+1)%4]);
+ UVCOPY(newFace[1]->tf.uv[1],face[1]->tf.uv[(p3+2)%4]);
+ UVCOPY(newFace[1]->tf.uv[2],face[1]->tf.uv[(p3+3)%4]);
+ UVCOPY(newFace[1]->tf.uv[3],face[0]->tf.uv[(p1+1)%4]);
+ }
+ else{
+ /*This should never happen*/
+ return;
+ }
+
+ if(fac1 == 3)
+ newFace[0]->e3->f |= 2;
+ else if(fac1 == 4)
+ newFace[0]->e4->f |= 2;
+
+
+ /* mark the f1's of the verts for re-selection */
+ faces[0][(p1+1)%fac1]->f1 |= 1;
+ faces[1][(p3+1)%fac2]->f1 |= 1;
+
+ /* get rid of the old edge and faces*/
+ remedge(eed);
+ free_editedge(eed);
+ BLI_remlink(&em->faces, face[0]);
+ free_editface(face[0]);
+ BLI_remlink(&em->faces, face[1]);
+ free_editface(face[1]);
+
+ return;
+}
+
+
+void edge_rotate_selected(){
+ EditEdge *eed,*temp;
+ EditVert *ev;
+ short edgeCount = 0;
+
+ undo_push_mesh("Rotate Edges");
+
+ /* Clear the f1 flag */
+ for(ev = G.editMesh->verts.first;ev;ev = ev->next)
+ ev->f1 &= ~1;
+
+ /*clear new flag for new edges*/
+ for(eed = G.editMesh->edges.first;eed;eed = eed->next){
+ eed->f &= ~2;
+ edgeCount++;
+ }
+ eed = G.editMesh->edges.first;
+ while(eed){
+ if(edgeCount-- < 0){
+ /* To prevent an infinite loop */
+ break;
+ }
+ if(eed->f & 2){
+ /* Do not rotate newly created edges */
+ eed = eed->next;
+ continue;
+ }
+ if(eed->v1->f & 1 && eed->v2->f & 1){
+ temp = eed;
+ eed = eed->next;
+ edge_rotate(temp);
+ } else
+ eed = eed->next;
+
+ }
+ /* clear all selections */
+ for(ev = G.editMesh->verts.first;ev;ev = ev->next)
+ ev->f &= ~1;
+
+ /*set new selections*/
+ for(ev = G.editMesh->verts.first;ev;ev = ev->next){
+ if(ev->f1 & 1)
+ ev->f |= 1;
+ }
+
+ /*clear new edge flags*/
+ for(eed = G.editMesh->edges.first; eed; eed = eed->next)
+ eed->f &= ~2;
+
+ force_draw_all();
+ screen_swapbuffers();
+ return;
+}
+
+/******************* BEVEL CODE STARTS HERE ********************/
+
+void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3])
+{
+ float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac;
+
+ VecSubf(a, v1, v2);
+ VecSubf(c, v3, v2);
+
+ Crossf(n_a, a, no);
+ Normalise(n_a);
+ Crossf(n_c, no, c);
+ Normalise(n_c);
+
+ Normalise(a);
+ Normalise(c);
+ ac = Inpf(a, c);
+
+ if (ac == 1 || ac == -1) {
+ midvec[0] = midvec[1] = midvec[2] = 0;
+ return;
+ }
+ ac2 = ac * ac;
+ fac = sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1);
+ VecAddf(mid, n_c, n_a);
+ Normalise(mid);
+ VecMulf(mid, d * fac);
+ VecAddf(mid, mid, v2);
+ VecCopyf(midvec, mid);
+}
+
+/* Finds the new point using the sinus law to extrapolate a triangle
+ Lots of sqrts which would not be good for a real time algo
+ Using the mid point of the extrapolation of both sides
+ Useless for coplanar quads, but that doesn't happen too often */
+void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3])
+{
+ float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3];
+
+ VecSubf(a, v3, v2);
+ l_a = Normalise(a);
+ VecSubf(b, v4, v3);
+ Normalise(b);
+ VecSubf(c, v1, v2);
+ Normalise(c);
+
+ s_b = Inpf(a, c);
+ s_b = sqrt(1 - (s_b * s_b));
+ s_a = Inpf(b, c);
+ s_a = sqrt(1 - (s_a * s_a));
+ VecMulf(a, -1);
+ s_c = Inpf(a, b);
+ s_c = sqrt(1 - (s_c * s_c));
+
+ l_b = s_b * l_a / s_a;
+ l_c = s_c * l_a / s_a;
+
+ VecMulf(b, l_b);
+ VecMulf(c, l_c);
+
+ VecAddf(Pos1, v2, c);
+ VecAddf(Pos2, v3, b);
+
+ VecAddf(Dir, Pos1, Pos2);
+ VecMulf(Dir, 0.5);
+
+ bevel_displace_vec(midvec, v3, Dir, v2, d, no);
+
+}
+
+
+char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no)
+{
+ float o_a[3], a[3], o_c[3], c[3];
+
+ VecSubf(o_a, o_v1, o_v2);
+ VecSubf(a, v1, v2);
+
+ Crossf(o_c, o_a, no);
+ Crossf(c, a, no);
+
+ if (Inpf(c, o_c) <= 0)
+ return 1;
+ else
+ return 0;
+}
+
+// Detects and fix a quad wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal
+void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no)
+{
+ float vec[3];
+ char wrap[4];
+
+ // Quads can wrap partially. Watch out
+ wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2
+ wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3
+ wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4
+ wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1
+
+ // Edge 1 inverted
+ if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ }
+ // Edge 2 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+ // Edge 3 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) {
+ fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no);
+ VECCOPY(v4, vec);
+ VECCOPY(v1, vec);
+ }
+ // Edge 2 and 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) {
+ VecAddf(vec, v2, v3);
+ VecMulf(vec, 0.5);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ VecAddf(vec, v1, v4);
+ VecMulf(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 1 and 3 inverted
+ else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ VecAddf(vec, v1, v2);
+ VecMulf(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VecAddf(vec, v3, v4);
+ VecMulf(vec, 0.5);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Totally inverted
+ else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) {
+ VecAddf(vec, v1, v2);
+ VecAddf(vec, vec, v3);
+ VecAddf(vec, vec, v4);
+ VecMulf(vec, 0.25);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+
+}
+
+// Detects and fix a tri wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and the normal
+// Triangles cannot wrap partially (not in this situation
+void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no)
+{
+ if (detect_wrap(o_v1, o_v2, v1, v2, no)) {
+ float vec[3];
+ VecAddf(vec, o_v1, o_v2);
+ VecAddf(vec, vec, o_v3);
+ VecMulf(vec, 1.0/3.0);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+}
+
+void bevel_shrink_faces(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centres */
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & flag) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, efa->v1->co, efa->v2->co, efa->v3->co, no);
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(efa->v4->co, vec);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, d, no);
+ }
+ }
+ efa= efa->next;
+ }
+}
+
+void bevel_shrink_draw(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centres */
+ efa= em->faces.first;
+ while (efa) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv3);
+ glEnd();
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(fv4, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv3);
+ glVertex3fv(fv4);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv4);
+ glEnd();
+ }
+ efa= efa->next;
+ }
+}
+
+void bevel_mesh(float bsize, int allfaces)
+{
+ EditMesh *em = G.editMesh;
+//#define BEV_DEBUG
+/* Enables debug printfs and assigns material indices: */
+/* 2 = edge quad */
+/* 3 = fill polygon (vertex clusters) */
+
+ EditFace *efa, *example; //, *nextvl;
+ EditEdge *eed, *eed2;
+ EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4;
+ float con1, con2, con3;
+ //short found4, search;
+ //float f1, f2, f3, f4;
+ float cent[3], min[3], max[3];
+ int a, b, c;
+ float limit= 0.001;
+
+ waitcursor(1);
+
+ removedoublesflag(1, limit);
+
+ /* tag all original faces */
+ efa= em->faces.first;
+ while (efa) {
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 1;
+ efa->v1->f |= 128;
+ efa->v2->f |= 128;
+ efa->v3->f |= 128;
+ if (efa->v4) efa->v4->f |= 128;
+ }
+ efa->v1->f &= ~64;
+ efa->v2->f &= ~64;
+ efa->v3->f &= ~64;
+ if (efa->v4) efa->v4->f &= ~64;
+
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: split\n");
+#endif
+
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & 1) {
+ efa->f1-= 1;
+ v1= addvertlist(efa->v1->co);
+ v1->f= efa->v1->f & ~128;
+ efa->v1->vn= v1;
+#ifdef __NLA
+ v1->totweight = efa->v1->totweight;
+ if (efa->v1->totweight){
+ v1->dw = MEM_mallocN (efa->v1->totweight * sizeof(MDeformWeight), "deformWeight");
+ memcpy (v1->dw, efa->v1->dw, efa->v1->totweight * sizeof(MDeformWeight));
+ }
+ else
+ v1->dw=NULL;
+#endif
+ v1= addvertlist(efa->v2->co);
+ v1->f= efa->v2->f & ~128;
+ efa->v2->vn= v1;
+#ifdef __NLA
+ v1->totweight = efa->v2->totweight;
+ if (efa->v2->totweight){
+ v1->dw = MEM_mallocN (efa->v2->totweight * sizeof(MDeformWeight), "deformWeight");
+ memcpy (v1->dw, efa->v2->dw, efa->v2->totweight * sizeof(MDeformWeight));
+ }
+ else
+ v1->dw=NULL;
+#endif
+ v1= addvertlist(efa->v3->co);
+ v1->f= efa->v3->f & ~128;
+ efa->v3->vn= v1;
+#ifdef __NLA
+ v1->totweight = efa->v3->totweight;
+ if (efa->v3->totweight){
+ v1->dw = MEM_mallocN (efa->v3->totweight * sizeof(MDeformWeight), "deformWeight");
+ memcpy (v1->dw, efa->v3->dw, efa->v3->totweight * sizeof(MDeformWeight));
+ }
+ else
+ v1->dw=NULL;
+#endif
+ if (efa->v4) {
+ v1= addvertlist(efa->v4->co);
+ v1->f= efa->v4->f & ~128;
+ efa->v4->vn= v1;
+#ifdef __NLA
+ v1->totweight = efa->v4->totweight;
+ if (efa->v4->totweight){
+ v1->dw = MEM_mallocN (efa->v4->totweight * sizeof(MDeformWeight), "deformWeight");
+ memcpy (v1->dw, efa->v4->dw, efa->v4->totweight * sizeof(MDeformWeight));
+ }
+ else
+ v1->dw=NULL;
+#endif
+ }
+
+ /* Needs better adaption of creases? */
+ addedgelist(efa->e1->v1->vn, efa->e1->v2->vn, efa->e1);
+ addedgelist(efa->e2->v1->vn,efa->e2->v2->vn, efa->e2);
+ addedgelist(efa->e3->v1->vn,efa->e3->v2->vn, efa->e3);
+ if (efa->e4) addedgelist(efa->e4->v1->vn,efa->e4->v2->vn, efa->e4);
+
+ if(efa->v4) {
+ v1= efa->v1->vn;
+ v2= efa->v2->vn;
+ v3= efa->v3->vn;
+ v4= efa->v4->vn;
+ addfacelist(v1, v2, v3, v4, efa);
+ } else {
+ v1= efa->v1->vn;
+ v2= efa->v2->vn;
+ v3= efa->v3->vn;
+ addfacelist(v1, v2, v3, 0, efa);
+ }
+
+ efa= efa-> next;
+ } else {
+ efa= efa->next;
+ }
+ }
+
+ delfaceflag(128);
+
+ /* tag all faces for shrink*/
+ efa= em->faces.first;
+ while (efa) {
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 2;
+ }
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: make edge quads\n");
+#endif
+
+ /* find edges that are on each other and make quads between them */
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f= eed->f1= 0;
+ if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces) eed->f1 |= 4; /* original edges */
+ eed->vn= 0;
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while (eed) {
+ if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) {
+ eed2= em->edges.first;
+ while (eed2) {
+ if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) {
+ if (
+ (eed->v1 != eed2->v1) &&
+ (eed->v1 != eed2->v2) &&
+ (eed->v2 != eed2->v1) &&
+ (eed->v2 != eed2->v2) && (
+ ( VecCompare(eed->v1->co, eed2->v1->co, limit) &&
+ VecCompare(eed->v2->co, eed2->v2->co, limit) ) ||
+ ( VecCompare(eed->v1->co, eed2->v2->co, limit) &&
+ VecCompare(eed->v2->co, eed2->v1->co, limit) ) ) )
+ {
+
+#ifdef BEV_DEBUG
+ fprintf(stderr, "bevel_mesh: edge quad\n");
+#endif
+
+ eed->f1 |= 2; /* these edges are finished */
+ eed2->f1 |= 2;
+
+ example= NULL;
+ efa= em->faces.first; /* search example face (for mat_nr, ME_SMOOTH, ...) */
+ while (efa) {
+ if ( (efa->e1 == eed) ||
+ (efa->e2 == eed) ||
+ (efa->e3 == eed) ||
+ (efa->e4 && (efa->e4 == eed)) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+
+ neweve[0]= eed->v1; neweve[1]= eed->v2;
+ neweve[2]= eed2->v1; neweve[3]= eed2->v2;
+
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ efa= NULL;
+
+ if (VecCompare(eed->v1->co, eed2->v2->co, limit)) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example);
+ } else {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example);
+ }
+
+ if(efa) {
+ float inp;
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 1;
+#endif
+ } else fprintf(stderr,"bevel_mesh: error creating face\n");
+ }
+ eed2= NULL;
+ }
+ }
+ if (eed2) eed2= eed2->next;
+ }
+ }
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f= eed->f1= 0;
+ eed->f1= 0;
+ eed->v1->f1 &= ~1;
+ eed->v2->f1 &= ~1;
+ eed->vn= 0;
+ eed= eed->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: find clusters\n");
+#endif
+
+ /* Look for vertex clusters */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~(64|128);
+ eve->vn= NULL;
+ eve= eve->next;
+ }
+
+ /* eve->f: 128: first vertex in a list (->vn) */
+ /* 64: vertex is in a list */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve2= em->verts.first;
+ eve3= NULL;
+ while (eve2) {
+ if ((eve2 != eve) && ((eve2->f & (64|128))==0)) {
+ if (VecCompare(eve->co, eve2->co, limit)) {
+ if ((eve->f & (128|64)) == 0) {
+ /* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */
+ eve->f |= 128;
+ eve->vn= eve2;
+ eve3= eve2;
+ } else if ((eve->f & 64) == 0) {
+ /* fprintf(stderr," *\n"); */
+ if (eve3) eve3->vn= eve2;
+ eve2->f |= 64;
+ eve3= eve2;
+ }
+ }
+ }
+ eve2= eve2->next;
+ if (!eve2) {
+ if (eve3) eve3->vn= NULL;
+ }
+ }
+ eve= eve->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: shrink faces\n");
+#endif
+
+ bevel_shrink_faces(bsize, 2);
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: fill clusters\n");
+#endif
+
+ /* Make former vertex clusters faces */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~64;
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ if (eve->f & 128) {
+ eve->f &= ~128;
+ a= 0;
+ neweve[a]= eve;
+ eve2= eve->vn;
+ while (eve2) {
+ a++;
+ neweve[a]= eve2;
+ eve2= eve2->vn;
+ }
+ a++;
+ efa= NULL;
+ if (a>=3) {
+ example= NULL;
+ efa= em->faces.first; /* search example face */
+ while (efa) {
+ if ( (efa->v1 == neweve[0]) ||
+ (efa->v2 == neweve[0]) ||
+ (efa->v3 == neweve[0]) ||
+ (efa->v4 && (efa->v4 == neweve[0])) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: Making %d-gon\n", a);
+#endif
+ if (a>4) {
+ cent[0]= cent[1]= cent[2]= 0.0;
+ INIT_MINMAX(min, max);
+ for (b=0; b<a; b++) {
+ VecAddf(cent, cent, neweve[b]->co);
+ DO_MINMAX(neweve[b]->co, min, max);
+ }
+ cent[0]= (min[0]+max[0])/2;
+ cent[1]= (min[1]+max[1])/2;
+ cent[2]= (min[2]+max[2])/2;
+ eve2= addvertlist(cent);
+ eve2->f |= 1;
+ eed= em->edges.first;
+ while (eed) {
+ c= 0;
+ for (b=0; b<a; b++)
+ if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++;
+ if (c==2) {
+ if(exist_face(eed->v1, eed->v2, eve2, 0)==0) {
+ efa= addfacelist(eed->v1, eed->v2, eve2, 0, example);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ eed= eed->next;
+ }
+ } else if (a==4) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co);
+ con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co);
+ con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co);
+ if(con1>=con2 && con1>=con3)
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example);
+ else if(con2>=con1 && con2>=con3)
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example);
+ else
+ efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], example);
+ }
+ }
+ else if (a==3) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0)
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, example);
+ }
+ if(efa) {
+ float inp;
+ CalcNormFloat(neweve[0]->co, neweve[1]->co, neweve[2]->co, efa->n);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ }
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f1= 0;
+ eve->f &= ~(128|64);
+ eve->vn= NULL;
+ eve= eve->next;
+ }
+
+ recalc_editnormals();
+ waitcursor(0);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+
+ removedoublesflag(1, limit);
+
+#undef BEV_DEBUG
+}
+
+void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
+{
+ float d;
+ short nr;
+
+ d= bsize;
+ for (nr=0; nr<recurs; nr++) {
+ bevel_mesh(d, allfaces);
+ if (nr==0) d /= 3; else d /= 2;
+ }
+}
+
+void bevel_menu()
+{
+ char Finished = 0, Canceled = 0, str[100], Recalc = 0;
+ short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr;
+ float vec[3], d, drawd=0.0, centre[3], fac = 1;
+
+ getmouseco_areawin(mval);
+ oval[0] = mval[0]; oval[1] = mval[1];
+
+ // Silly hackish code to initialise the variable (warning if not done)
+ // while still drawing in the first iteration (and without using another variable)
+ curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
+
+ window_to_3d(centre, mval[0], mval[1]);
+
+ if(button(&recurs, 1, 4, "Recursion:")==0) return;
+
+ for (nr=0; nr<recurs-1; nr++) {
+ if (nr==0) fac += 1.0/3.0; else fac += 1.0/(3 * nr * 2.0);
+ }
+
+ SetBlenderCursor(SYSCURSOR);
+
+ while (Finished == 0)
+ {
+ getmouseco_areawin(mval);
+ if (mval[0] != curval[0] || mval[1] != curval[1] || (Recalc == 1))
+ {
+ Recalc = 0;
+ curval[0] = mval[0];
+ curval[1] = mval[1];
+
+ window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]);
+ d = Normalise(vec) / 10;
+
+
+ drawd = d * fac;
+ if (G.qual & LR_CTRLKEY)
+ drawd = (float) floor(drawd * 10.0)/10.0;
+ if (G.qual & LR_SHIFTKEY)
+ drawd /= 10;
+
+ /*------------- Preview lines--------------- */
+
+ /* uses callback mechanism to draw it all in current area */
+ scrarea_do_windraw(curarea);
+
+ /* set window matrix to perspective, default an area returns with buttons transform */
+ persp(PERSP_VIEW);
+ /* make a copy, for safety */
+ glPushMatrix();
+ /* multiply with the object transformation */
+ mymultmatrix(G.obedit->obmat);
+
+ glColor3ub(255, 255, 0);
+
+ // PREVIEW CODE GOES HERE
+ bevel_shrink_draw(drawd, 2);
+
+ /* restore matrix transform */
+ glPopMatrix();
+
+ sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd);
+ headerprint(str);
+
+ /* this also verifies other area/windows for clean swap */
+ screen_swapbuffers();
+
+ persp(PERSP_WIN);
+
+ glDrawBuffer(GL_FRONT);
+
+ BIF_ThemeColor(TH_WIRE);
+
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ glVertex2sv(mval);
+ glVertex2sv(oval);
+ glEnd();
+ setlinestyle(0);
+
+ persp(PERSP_VIEW);
+ glFlush(); // flush display for frontbuffer
+ glDrawBuffer(GL_BACK);
+ }
+ while(qtest()) {
+ unsigned 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 && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)){
+ if (event==RIGHTMOUSE || event==ESCKEY)
+ Canceled = 1;
+ Finished = 1;
+ }
+ else if (val && event==SPACEKEY) {
+ if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) {
+ drawd = d * fac;
+ Finished = 1;
+ }
+ }
+ else if (val) {
+ /* On any other keyboard event, recalc */
+ Recalc = 1;
+ }
+
+ }
+ }
+ if (Canceled==0) {
+ SetBlenderCursor(BC_WAITCURSOR);
+ undo_push_mesh("Bevel");
+ bevel_mesh_recurs(drawd/fac, recurs, 1);
+ righthandfaces(1);
+ SetBlenderCursor(SYSCURSOR);
+ }
+}
+
+/* *********** END BEVEL *********/
+
+
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index 87439b265e6..4d1d5e34099 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -95,6 +95,7 @@
#include "BIF_editview.h"
#include "BIF_interface.h"
#include "BIF_mainqueue.h"
+#include "BIF_meshtools.h"
#include "BIF_poseobject.h"
#include "BIF_renderwin.h"
#include "BIF_resources.h"
diff --git a/source/blender/src/meshtools.c b/source/blender/src/meshtools.c
new file mode 100644
index 00000000000..65f0187dc8e
--- /dev/null
+++ b/source/blender/src/meshtools.c
@@ -0,0 +1,883 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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 NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+meshtools.c: no editmode, tools operating on meshes
+
+void join_mesh(void);
+void make_sticky(void);
+
+void fasterdraw(void);
+void slowerdraw(void);
+
+void vertexnormals_mesh(Mesh *me, float *extverts);
+void sort_faces(void);
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_graphics.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_editobject.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "render.h" // bad level call (ton)
+
+/* * ********************** no editmode!!! *********** */
+
+
+/** tests whether selected mesh objects have tfaces */
+static int testSelected_TfaceMesh(void)
+{
+ Base *base;
+ Mesh *me;
+
+ base = FIRSTBASE;
+ while (base) {
+ if TESTBASE(base) {
+ if(base->object->type==OB_MESH) {
+ me= base->object->data;
+ if (me->tface)
+ return 1;
+ }
+ }
+ base= base->next;
+ }
+ return 0;
+}
+
+void join_mesh(void)
+{
+ Base *base, *nextb;
+ Object *ob;
+ Material **matar, *ma;
+ Mesh *me;
+ MVert *mvert, *mvertmain;
+ MEdge *medge = NULL, *medgemain;
+ MFace *mface = NULL, *mfacemain;
+ TFace *tface = NULL, *tfacemain;
+ unsigned int *mcol=NULL, *mcolmain;
+ float imat[4][4], cmat[4][4];
+ int a, b, totcol, totedge=0, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT];
+ int hasedges=0;
+ int i, j, index, haskey=0;
+ bDeformGroup *dg, *odg;
+ MDeformVert *dvert, *dvertmain;
+
+ if(G.obedit) return;
+
+ ob= OBACT;
+ if(!ob || ob->type!=OB_MESH) return;
+
+ /* count */
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+ if(base->object->type==OB_MESH) {
+ me= base->object->data;
+ totvert+= me->totvert;
+ totface+= me->totface;
+ if(me->medge) hasedges= 1;
+
+ if(base->object == ob) ok= 1;
+
+ if(me->key) {
+ haskey= 1;
+ break;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ if(haskey) {
+ error("Can't join meshes with vertex keys");
+ return;
+ }
+ /* that way the active object is always selected */
+ if(ok==0) return;
+
+ if(totvert==0 || totvert>MESH_MAX_VERTS) return;
+
+ if(okee("Join selected meshes")==0) return;
+
+
+ /* if needed add edges to other meshes */
+ if(hasedges) {
+ for(base= FIRSTBASE; base; base= base->next) {
+ if TESTBASE(base) {
+ if(base->object->type==OB_MESH) {
+ me= base->object->data;
+ if(me->medge==NULL) make_edges(me);
+ totedge += me->totedge;
+ }
+ }
+ }
+ }
+
+ /* new material indices and material array */
+ matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh");
+ totcol= ob->totcol;
+
+ /* obact materials in new main array, is nicer start! */
+ for(a=1; a<=ob->totcol; a++) {
+ matar[a-1]= give_current_material(ob, a);
+ id_us_plus((ID *)matar[a-1]);
+ /* increase id->us : will be lowered later */
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+ if(ob!=base->object && base->object->type==OB_MESH) {
+ me= base->object->data;
+
+ // Join this object's vertex groups to the base one's
+ for (dg=base->object->defbase.first; dg; dg=dg->next){
+ /* See if this group exists in the object */
+ for (odg=ob->defbase.first; odg; odg=odg->next){
+ if (!strcmp(odg->name, dg->name)){
+ break;
+ }
+ }
+ if (!odg){
+ odg = MEM_callocN (sizeof(bDeformGroup), "deformGroup");
+ memcpy (odg, dg, sizeof(bDeformGroup));
+ BLI_addtail(&ob->defbase, odg);
+ }
+
+ }
+ if (ob->defbase.first && ob->actdef==0)
+ ob->actdef=1;
+
+ if(me->totvert) {
+ for(a=1; a<=base->object->totcol; a++) {
+ ma= give_current_material(base->object, a);
+ if(ma) {
+ for(b=0; b<totcol; b++) {
+ if(ma == matar[b]) break;
+ }
+ if(b==totcol) {
+ matar[b]= ma;
+ ma->id.us++;
+ totcol++;
+ }
+ if(totcol>=MAXMAT-1) break;
+ }
+ }
+ }
+ }
+ if(totcol>=MAXMAT-1) break;
+ }
+ base= base->next;
+ }
+
+ me= ob->data;
+ mvert= mvertmain= MEM_mallocN(totvert*sizeof(MVert), "joinmesh vert");
+
+ if(totedge) medge= medgemain= MEM_callocN(totedge*sizeof(MEdge), "joinmesh edge");
+ else medgemain= NULL;
+
+ if (totface) mface= mfacemain= MEM_mallocN(totface*sizeof(MFace), "joinmesh face");
+ else mfacemain= NULL;
+
+ if(me->mcol) mcol= mcolmain= MEM_callocN(totface*4*sizeof(int), "joinmesh mcol");
+ else mcolmain= NULL;
+
+ /* if active object doesn't have Tfaces, but one in the selection does,
+ make TFaces for active, so we don't lose texture information in the
+ join process */
+ if(me->tface || testSelected_TfaceMesh()) tface= tfacemain= MEM_callocN(totface*4*sizeof(TFace), "joinmesh4");
+ else tfacemain= NULL;
+
+ if(me->dvert)
+ dvert= dvertmain= MEM_callocN(totvert*sizeof(MDeformVert), "joinmesh5");
+ else dvert=dvertmain= NULL;
+
+ vertofs= 0;
+
+ /* inverse transorm all selected meshes in this object */
+ Mat4Invert(imat, ob->obmat);
+
+ base= FIRSTBASE;
+ while(base) {
+ nextb= base->next;
+ if TESTBASE(base) {
+ if(base->object->type==OB_MESH) {
+
+ me= base->object->data;
+
+ if(me->totvert) {
+
+ memcpy(mvert, me->mvert, me->totvert*sizeof(MVert));
+
+ copy_dverts(dvert, me->dvert, me->totvert);
+
+ /* NEW VERSION */
+ if (dvertmain){
+ for (i=0; i<me->totvert; i++){
+ for (j=0; j<dvert[i].totweight; j++){
+ // Find the old vertex group
+ odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr);
+ if(odg) {
+ // Search for a match in the new object
+ for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){
+ if (!strcmp(dg->name, odg->name)){
+ dvert[i].dw[j].def_nr = index;
+ break;
+ }
+ }
+ }
+ }
+ }
+ dvert+=me->totvert;
+ }
+
+ if(base->object != ob) {
+ /* watch this: switch matmul order really goes wrong */
+ Mat4MulMat4(cmat, base->object->obmat, imat);
+
+ a= me->totvert;
+ while(a--) {
+ Mat4MulVecfl(cmat, mvert->co);
+ mvert++;
+ }
+ }
+ else mvert+= me->totvert;
+
+ if(mcolmain) {
+ if(me->mcol) memcpy(mcol, me->mcol, me->totface*4*4);
+ mcol+= 4*me->totface;
+ }
+ }
+ if(me->totface) {
+
+ /* make mapping for materials */
+ memset(map, 0, 4*MAXMAT);
+ for(a=1; a<=base->object->totcol; a++) {
+ ma= give_current_material(base->object, a);
+ if(ma) {
+ for(b=0; b<totcol; b++) {
+ if(ma == matar[b]) {
+ map[a-1]= b;
+ break;
+ }
+ }
+ }
+ }
+
+ memcpy(mface, me->mface, me->totface*sizeof(MFace));
+
+ a= me->totface;
+ while(a--) {
+ mface->v1+= vertofs;
+ mface->v2+= vertofs;
+ if(mface->v3) mface->v3+= vertofs;
+ if(mface->v4) mface->v4+= vertofs;
+
+ mface->mat_nr= map[(int)mface->mat_nr];
+
+ mface++;
+ }
+
+ if(tfacemain) {
+ if(me->tface) memcpy(tface, me->tface, me->totface*sizeof(TFace));
+ tface+= me->totface;
+ }
+
+ }
+
+ if(me->totedge) {
+ memcpy(medge, me->medge, me->totedge*sizeof(MEdge));
+
+ a= me->totedge;
+ while(a--) {
+ medge->v1+= vertofs;
+ medge->v2+= vertofs;
+ medge++;
+ }
+ }
+
+ vertofs+= me->totvert;
+
+ if(base->object!=ob) {
+ free_and_unlink_base(base);
+ }
+ }
+ }
+ base= nextb;
+ }
+
+ me= ob->data;
+
+ if(me->mvert) MEM_freeN(me->mvert);
+ me->mvert= mvertmain;
+
+ if(me->medge) MEM_freeN(me->medge);
+ me->medge= medgemain;
+
+ if(me->mface) MEM_freeN(me->mface);
+ me->mface= mfacemain;
+
+ if(me->dvert) free_dverts(me->dvert, me->totvert);
+ me->dvert = dvertmain;
+
+ if(me->mcol) MEM_freeN(me->mcol);
+ me->mcol= (MCol *)mcolmain;
+
+ if(me->tface) MEM_freeN(me->tface);
+ me->tface= tfacemain;
+
+ me->totvert= totvert;
+ me->totedge= totedge;
+ me->totface= totface;
+
+ /* old material array */
+ for(a=1; a<=ob->totcol; a++) {
+ ma= ob->mat[a-1];
+ if(ma) ma->id.us--;
+ }
+ for(a=1; a<=me->totcol; a++) {
+ ma= me->mat[a-1];
+ if(ma) ma->id.us--;
+ }
+ if(ob->mat) MEM_freeN(ob->mat);
+ if(me->mat) MEM_freeN(me->mat);
+ ob->mat= me->mat= 0;
+
+ if(totcol) {
+ me->mat= matar;
+ ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
+ }
+ else MEM_freeN(matar);
+
+ ob->totcol= me->totcol= totcol;
+ ob->colbits= 0;
+
+ /* other mesh users */
+ test_object_materials((ID *)me);
+
+ enter_editmode();
+ exit_editmode(1); // freedata, but no undo
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ makeDispList(ob);
+
+ BIF_undo_push("Join Mesh");
+}
+
+
+void make_sticky(void)
+{
+ Object *ob;
+ Base *base;
+ MVert *mvert;
+ Mesh *me;
+ MSticky *ms;
+ float ho[4], mat[4][4];
+ int a;
+
+ if(G.scene->camera==0) return;
+
+ if(G.obedit) {
+ error("Unable to make sticky in Edit Mode");
+ return;
+ }
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base->object->type==OB_MESH) {
+ ob= base->object;
+
+ me= ob->data;
+ mvert= me->mvert;
+ if(me->msticky) MEM_freeN(me->msticky);
+ me->msticky= MEM_mallocN(me->totvert*sizeof(MSticky), "sticky");
+
+ /* like convert to render data */
+ R.r= G.scene->r;
+ R.r.xsch= (R.r.size*R.r.xsch)/100;
+ R.r.ysch= (R.r.size*R.r.ysch)/100;
+
+ R.afmx= R.r.xsch/2;
+ R.afmy= R.r.ysch/2;
+
+ R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp);
+
+ R.rectx= R.r.xsch;
+ R.recty= R.r.ysch;
+ R.xstart= -R.afmx;
+ R.ystart= -R.afmy;
+ R.xend= R.xstart+R.rectx-1;
+ R.yend= R.ystart+R.recty-1;
+
+ where_is_object(G.scene->camera);
+ Mat4CpyMat4(R.viewinv, G.scene->camera->obmat);
+ Mat4Ortho(R.viewinv);
+ Mat4Invert(R.viewmat, R.viewinv);
+
+ RE_setwindowclip(1, -1);
+
+ where_is_object(ob);
+ Mat4MulMat4(mat, ob->obmat, R.viewmat);
+
+ ms= me->msticky;
+ for(a=0; a<me->totvert; a++, ms++, mvert++) {
+ VECCOPY(ho, mvert->co);
+ Mat4MulVecfl(mat, ho);
+ RE_projectverto(ho, ho);
+ ms->co[0]= ho[0]/ho[3];
+ ms->co[1]= ho[1]/ho[3];
+ }
+ }
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+void fasterdraw(void)
+{
+ Base *base;
+ Mesh *me;
+ MFace *mface;
+ int toggle, a;
+
+ if(G.obedit) return;
+
+ /* reset flags */
+ me= G.main->mesh.first;
+ while(me) {
+ me->flag &= ~ME_ISDONE;
+ me= me->id.next;
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
+ me= base->object->data;
+ if(me->id.lib==0 && (me->flag & ME_ISDONE)==0) {
+ me->flag |= ME_ISDONE;
+ mface= me->mface;
+ toggle= 0;
+ for(a=0; a<me->totface; a++) {
+ if( (mface->edcode & ME_V1V2) && ( (toggle++) & 1) ) {
+ mface->edcode-= ME_V1V2;
+ }
+ if( (mface->edcode & ME_V2V3) && ( (toggle++) & 1)) {
+ mface->edcode-= ME_V2V3;
+ }
+ if( (mface->edcode & ME_V3V1) && ( (toggle++) & 1)) {
+ mface->edcode-= ME_V3V1;
+ }
+ if( (mface->edcode & ME_V4V1) && ( (toggle++) & 1)) {
+ mface->edcode-= ME_V4V1;
+ }
+ if( (mface->edcode & ME_V3V4) && ( (toggle++) & 1)) {
+ mface->edcode-= ME_V3V4;
+ }
+ mface++;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ /* important?: reset flags again */
+ me= G.main->mesh.first;
+ while(me) {
+ me->flag &= ~ME_ISDONE;
+ me= me->id.next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void slowerdraw(void) /* reset fasterdraw */
+{
+ Base *base;
+ Mesh *me;
+ MFace *mface;
+ int a;
+
+ if(G.obedit) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
+ me= base->object->data;
+ if(me->id.lib==0) {
+
+ mface= me->mface;
+
+ for(a=0; a<me->totface; a++) {
+
+ mface->edcode |= ME_V1V2|ME_V2V3;
+ mface++;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+/* ***************** */
+
+/* this one for NOT in editmode
+
+(only used by external modules, that is, until now by the
+python NMesh module)
+
+TODO: Probably it's better to convert the mesh into a EditMesh, call
+vertexnormals() and convert it back to a Mesh again.
+
+*/
+
+static int contrpuntnorm(float *n, float *puno) /* dutch: check vertex normal */
+{
+ float inp;
+
+ inp= n[0]*puno[0]+n[1]*puno[1]+n[2]*puno[2];
+
+ /* angles 90 degrees: dont flip */
+ if(inp> -0.000001) return 0;
+
+ return 1;
+}
+
+void vertexnormals_mesh(Mesh *me, float *extverts)
+{
+ MVert *mvert;
+ MFace *mface;
+ float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp;
+ float *f1, *f2, *f3, *f4, xn, yn, zn, *normals;
+ float *v1, *v2, *v3, *v4, len, vnor[3];
+ int a, testflip;
+
+ if(me->totvert==0) return;
+
+ testflip= (me->flag & ME_NOPUNOFLIP)==0;
+ if((me->flag & ME_TWOSIDED)==0) testflip= 0; /* large angles */
+
+ if(me->totface==0) {
+ /* fake vertex normals for 'halopuno' (render option) */
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ VECCOPY(n1, mvert->co);
+ Normalise(n1);
+ mvert->no[0]= 32767.0*n1[0];
+ mvert->no[1]= 32767.0*n1[1];
+ mvert->no[2]= 32767.0*n1[2];
+ }
+ return;
+ }
+
+ normals= MEM_callocN(me->totvert*3*sizeof(float), "normals");
+
+ /* calculate cosine angles, and add to vertex normal */
+ mface= me->mface;
+ mvert= me->mvert;
+ for(a=0; a<me->totface; a++, mface++) {
+
+ if(mface->v3==0) continue;
+
+ if(extverts) {
+ v1= extverts+3*mface->v1;
+ v2= extverts+3*mface->v2;
+ v3= extverts+3*mface->v3;
+ v4= extverts+3*mface->v4;
+ }
+ else {
+ v1= (mvert+mface->v1)->co;
+ v2= (mvert+mface->v2)->co;
+ v3= (mvert+mface->v3)->co;
+ v4= (mvert+mface->v4)->co;
+ }
+
+ VecSubf(n1, v2, v1);
+ VecSubf(n2, v3, v2);
+ Normalise(n1);
+ Normalise(n2);
+
+ if(mface->v4==0) {
+ VecSubf(n3, v1, v3);
+ Normalise(n3);
+
+ co[0]= saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]);
+ co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+
+ }
+ else {
+ VecSubf(n3, v4, v3);
+ VecSubf(n4, v1, v4);
+ Normalise(n3);
+ Normalise(n4);
+
+ co[0]= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
+ co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+ co[3]= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
+ }
+
+ CalcNormFloat(v1, v2, v3, vnor);
+
+ temp= normals+3*mface->v1;
+ if(testflip && contrpuntnorm(vnor, temp) ) co[0]= -co[0];
+ temp[0]+= co[0]*vnor[0];
+ temp[1]+= co[0]*vnor[1];
+ temp[2]+= co[0]*vnor[2];
+
+ temp= normals+3*mface->v2;
+ if(testflip && contrpuntnorm(vnor, temp) ) co[1]= -co[1];
+ temp[0]+= co[1]*vnor[0];
+ temp[1]+= co[1]*vnor[1];
+ temp[2]+= co[1]*vnor[2];
+
+ temp= normals+3*mface->v3;
+ if(testflip && contrpuntnorm(vnor, temp) ) co[2]= -co[2];
+ temp[0]+= co[2]*vnor[0];
+ temp[1]+= co[2]*vnor[1];
+ temp[2]+= co[2]*vnor[2];
+
+ if(mface->v4) {
+ temp= normals+3*mface->v4;
+ if(testflip && contrpuntnorm(vnor, temp) ) co[3]= -co[3];
+ temp[0]+= co[3]*vnor[0];
+ temp[1]+= co[3]*vnor[1];
+ temp[2]+= co[3]*vnor[2];
+ }
+ }
+
+ /* normalize vertex normals */
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ len= Normalise(normals+3*a);
+ if(len!=0.0) {
+ VECCOPY(n1, normals+3*a);
+ Normalise(n1);
+
+ mvert->no[0]= 32767.0*n1[0];
+ mvert->no[1]= 32767.0*n1[1];
+ mvert->no[2]= 32767.0*n1[2];
+ }
+ }
+
+ /* vertex normal flipping flags, for during render */
+ mface= me->mface;
+ mvert= me->mvert;
+ for(a=0; a<me->totface; a++, mface++) {
+ mface->puno=0;
+
+ if(mface->v3==0) continue;
+
+ if(extverts) {
+ v1= extverts+3*mface->v1;
+ v2= extverts+3*mface->v2;
+ v3= extverts+3*mface->v3;
+ }
+ else {
+ v1= (mvert+mface->v1)->co;
+ v2= (mvert+mface->v2)->co;
+ v3= (mvert+mface->v3)->co;
+ }
+
+ CalcNormFloat(v1, v2, v3, vnor);
+
+ if(testflip) {
+ f1= normals + 3*mface->v1;
+ f2= normals + 3*mface->v2;
+ f3= normals + 3*mface->v3;
+
+ fac1= vnor[0]*f1[0] + vnor[1]*f1[1] + vnor[2]*f1[2];
+ if(fac1<0.0) {
+ mface->puno = ME_FLIPV1;
+ }
+ fac2= vnor[0]*f2[0] + vnor[1]*f2[1] + vnor[2]*f2[2];
+ if(fac2<0.0) {
+ mface->puno += ME_FLIPV2;
+ }
+ fac3= vnor[0]*f3[0] + vnor[1]*f3[1] + vnor[2]*f3[2];
+ if(fac3<0.0) {
+ mface->puno += ME_FLIPV3;
+ }
+ if(mface->v4) {
+ f4= normals + 3*mface->v4;
+ fac4= vnor[0]*f4[0] + vnor[1]*f4[1] + vnor[2]*f4[2];
+ if(fac4<0.0) {
+ mface->puno += ME_FLIPV4;
+ }
+ }
+ }
+ /* proj for cubemap! */
+ xn= fabs(vnor[0]);
+ yn= fabs(vnor[1]);
+ zn= fabs(vnor[2]);
+
+ if(zn>xn && zn>yn) mface->puno += ME_PROJXY;
+ else if(yn>xn && yn>zn) mface->puno += ME_PROJXZ;
+ else mface->puno += ME_PROJYZ;
+
+ }
+
+ MEM_freeN(normals);
+}
+
+
+
+/* ********************** 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);
+}
+
+static MVert *mvertbase;
+static MFace *mfacebase;
+
+static int verg_mface(const void *v1, const void *v2)
+{
+ MFace *x1, *x2;
+
+ MVert *ve1, *ve2;
+ int i1, i2;
+
+ i1 = ((int *) v1)[0];
+ i2 = ((int *) v2)[0];
+
+ x1 = mfacebase + i1;
+ x2 = mfacebase + i2;
+
+ ve1= mvertbase+x1->v1;
+ ve2= mvertbase+x2->v1;
+
+ if( ve1->co[2] > ve2->co[2] ) return 1;
+ else if( ve1->co[2] < ve2->co[2]) return -1;
+ return 0;
+}
+
+
+void sort_faces(void)
+{
+ Object *ob= OBACT;
+ Mesh *me;
+
+ int i, *index;
+
+ if(ob==0) return;
+ if(G.obedit) return;
+ if(ob->type!=OB_MESH) return;
+
+ if(okee("Sort faces in Z axis")==0) return;
+ me= ob->data;
+ if(me->totface==0) return;
+
+/* create index list */
+ index = (int *) MEM_mallocN(sizeof(int) * me->totface, "sort faces");
+ for (i = 0; i < me->totface; i++) {
+ index[i] = i;
+ }
+ mvertbase= me->mvert;
+ mfacebase = me->mface;
+
+/* sort index list instead of faces itself
+ and apply this permutation to the face list plus
+ to the texture faces */
+ qsort(index, me->totface, sizeof(int), verg_mface);
+
+ permutate(mfacebase, me->totface, sizeof(MFace), index);
+ if (me->tface)
+ permutate(me->tface, me->totface, sizeof(TFace), index);
+
+ MEM_freeN(index);
+
+ allqueue(REDRAWVIEW3D, 0);
+ makeDispList(G.obedit);
+}
+
+
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 5e93dc2d42e..aa5e9864392 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -100,6 +100,7 @@
#include "BIF_gl.h"
#include "BIF_imasel.h"
#include "BIF_interface.h"
+#include "BIF_meshtools.h"
#include "BIF_mywindow.h"
#include "BIF_oops.h"
#include "BIF_resources.h"
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
index 8b006ba2e38..ec75739b4e5 100644
--- a/source/blender/src/usiblender.c
+++ b/source/blender/src/usiblender.c
@@ -564,7 +564,6 @@ void exit_usiblender(void)
free_posebuf();
free_blender(); /* blender.c, does entire library */
- free_hashedgetab();
free_matcopybuf();
free_ipocopybuf();
freefastshade();