diff options
author | Ton Roosendaal <ton@blender.org> | 2004-09-19 15:47:49 +0400 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2004-09-19 15:47:49 +0400 |
commit | ca5b7386e501518157493335e870435017cbb98a (patch) | |
tree | deb4d80d9e371fd5393a12c18698128b98bcfaa4 | |
parent | dab46067bf3c3b808a7ba5071e0d51d753651674 (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)
-rw-r--r-- | source/blender/include/BIF_editmesh.h | 193 | ||||
-rw-r--r-- | source/blender/include/BIF_meshtools.h | 47 | ||||
-rw-r--r-- | source/blender/include/editmesh.h | 89 | ||||
-rw-r--r-- | source/blender/src/booleanops.c | 2 | ||||
-rw-r--r-- | source/blender/src/buttons_editing.c | 1 | ||||
-rw-r--r-- | source/blender/src/editmesh.c | 8805 | ||||
-rw-r--r-- | source/blender/src/editmesh_add.c | 699 | ||||
-rw-r--r-- | source/blender/src/editmesh_lib.c | 736 | ||||
-rw-r--r-- | source/blender/src/editmesh_loop.c | 1843 | ||||
-rw-r--r-- | source/blender/src/editmesh_mods.c | 1447 | ||||
-rw-r--r-- | source/blender/src/editmesh_tools.c | 3446 | ||||
-rw-r--r-- | source/blender/src/header_view3d.c | 1 | ||||
-rw-r--r-- | source/blender/src/meshtools.c | 883 | ||||
-rw-r--r-- | source/blender/src/space.c | 1 | ||||
-rw-r--r-- | source/blender/src/usiblender.c | 1 |
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(); |