- Added EM_project_snap_verts so other functions can re-use this, similar to old retopo_do_all(). - Changed how the normal for selected geometry is calculated, was accumulating half selected edge's into normals which was OK with even surrounding geometry but could skew too easily if the surroundings were not so even. Now use the 2D screen space selected edge vector to calculate the normals in relation to the target mouse position. - Option to rotate initial selection, gives better results in some cases. (Ctrl+Shift+Click to disable) http://wiki.blender.org/index.php/File:ClickExtrudeFix.png
		
			
				
	
	
		
			1756 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1756 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						|
 * $Id$
 | 
						|
 *
 | 
						|
 * ***** BEGIN GPL LICENSE BLOCK *****
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public License
 | 
						|
 * as published by the Free Software Foundation; either version 2
 | 
						|
 * of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 * The Original Code is Copyright (C) 2004 by Blender Foundation.
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * The Original Code is: all of this file.
 | 
						|
 *
 | 
						|
 * Contributor(s): none yet.
 | 
						|
 *
 | 
						|
 * ***** END GPL LICENSE BLOCK *****
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <math.h>
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
#include "DNA_meshdata_types.h"
 | 
						|
#include "DNA_object_types.h"
 | 
						|
#include "DNA_scene_types.h"
 | 
						|
 | 
						|
#include "RNA_define.h"
 | 
						|
#include "RNA_access.h"
 | 
						|
 | 
						|
#include "BLI_blenlib.h"
 | 
						|
#include "BLI_math.h"
 | 
						|
#include "BLI_editVert.h"
 | 
						|
 | 
						|
#include "BKE_context.h"
 | 
						|
#include "BKE_depsgraph.h"
 | 
						|
#include "BKE_library.h"
 | 
						|
#include "BKE_mesh.h"
 | 
						|
#include "BKE_report.h"
 | 
						|
 | 
						|
#include "WM_api.h"
 | 
						|
#include "WM_types.h"
 | 
						|
 | 
						|
#include "ED_mesh.h"
 | 
						|
#include "ED_screen.h"
 | 
						|
#include "ED_transform.h"
 | 
						|
#include "ED_view3d.h"
 | 
						|
#include "ED_object.h"
 | 
						|
 | 
						|
#include "mesh_intern.h"
 | 
						|
 | 
						|
/* bpymenu removed XXX */
 | 
						|
 | 
						|
/* XXX */
 | 
						|
#define add_numbut(a, b, c, d, e, f, g) {}
 | 
						|
/* XXX */
 | 
						|
 | 
						|
static float icovert[12][3] = {
 | 
						|
	{0.0f,0.0f,-200.0f}, 
 | 
						|
	{144.72f, -105.144f,-89.443f},
 | 
						|
	{-55.277f, -170.128,-89.443f}, 
 | 
						|
	{-178.885f,0.0f,-89.443f},
 | 
						|
	{-55.277f,170.128f,-89.443f}, 
 | 
						|
	{144.72f,105.144f,-89.443f},
 | 
						|
	{55.277f,-170.128f,89.443f},
 | 
						|
	{-144.72f,-105.144f,89.443f},
 | 
						|
	{-144.72f,105.144f,89.443f},
 | 
						|
	{55.277f,170.128f,89.443f},
 | 
						|
	{178.885f,0.0f,89.443f},
 | 
						|
	{0.0f,0.0f,200.0f}
 | 
						|
};
 | 
						|
static short icoface[20][3] = {
 | 
						|
	{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}
 | 
						|
};
 | 
						|
 | 
						|
/* *************** add-click-mesh (extrude) operator ************** */
 | 
						|
 | 
						|
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
 | 
						|
{
 | 
						|
	ViewContext vc;
 | 
						|
	EditVert *eve;
 | 
						|
	float min[3], max[3];
 | 
						|
	int done= 0;
 | 
						|
	int rot_src= RNA_boolean_get(op->ptr, "rotate_source");
 | 
						|
	
 | 
						|
	em_setup_viewcontext(C, &vc);
 | 
						|
	
 | 
						|
	invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); 
 | 
						|
	
 | 
						|
	INIT_MINMAX(min, max);
 | 
						|
	
 | 
						|
	for(eve= vc.em->verts.first; eve; eve= eve->next) {
 | 
						|
		if(eve->f & SELECT) {
 | 
						|
			DO_MINMAX(eve->co, min, max);
 | 
						|
			done= 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* call extrude? */
 | 
						|
	if(done) {
 | 
						|
		EditEdge *eed;
 | 
						|
		float vec[3], cent[3], mat[3][3];
 | 
						|
		float nor[3]= {0.0, 0.0, 0.0};
 | 
						|
		
 | 
						|
		/* 2D normal calc */
 | 
						|
		float mval_f[2]= {(float)event->mval[0], (float)event->mval[1]};
 | 
						|
 | 
						|
#define SIDE_OF_LINE(pa,pb,pp)	((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
 | 
						|
		
 | 
						|
		done= 0;
 | 
						|
 | 
						|
		/* calculate the normal for selected edges */
 | 
						|
		for(eed= vc.em->edges.first; eed; eed= eed->next) {
 | 
						|
			if(eed->f & SELECT) {
 | 
						|
				float co1[3], co2[3];
 | 
						|
				mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co);
 | 
						|
				mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co);
 | 
						|
				project_float_noclip(vc.ar, co1, co1);
 | 
						|
				project_float_noclip(vc.ar, co2, co2);
 | 
						|
				
 | 
						|
				/* 2D rotate by 90d while subtracting
 | 
						|
				 *  (x, y) = (y, -x)
 | 
						|
				 *
 | 
						|
				 * accumulate the screenspace normal in 2D,
 | 
						|
				 * with screenspace edge length weighting the result. */
 | 
						|
				if(SIDE_OF_LINE(co1, co2, mval_f) >= 0.0f) {
 | 
						|
					nor[0] +=  (co1[1] - co2[1]);
 | 
						|
					nor[1] += -(co1[0] - co2[0]);
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					nor[0] +=  (co2[1] - co1[1]);
 | 
						|
					nor[1] += -(co2[0] - co1[0]);
 | 
						|
				}
 | 
						|
				done= 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
#undef SIDE_OF_LINE
 | 
						|
 | 
						|
		if(done) {
 | 
						|
			float view_vec[3], cross[3];
 | 
						|
 | 
						|
			/* convert the 2D nomal into 3D */
 | 
						|
			mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
 | 
						|
			mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
 | 
						|
			
 | 
						|
			/* correct the normal to be aligned on the view plane */
 | 
						|
			copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
 | 
						|
			mul_mat3_m4_v3(vc.obedit->imat, view_vec);
 | 
						|
			cross_v3_v3v3(cross, nor, view_vec);
 | 
						|
			cross_v3_v3v3(nor, view_vec, cross);
 | 
						|
			normalize_v3(nor);
 | 
						|
			
 | 
						|
			/* correct for flipping */
 | 
						|
		}
 | 
						|
		
 | 
						|
		/* center */
 | 
						|
		add_v3_v3v3(cent, min, max);
 | 
						|
		mul_v3_fl(cent, 0.5f);
 | 
						|
		VECCOPY(min, cent);
 | 
						|
		
 | 
						|
		mul_m4_v3(vc.obedit->obmat, min);	// view space
 | 
						|
		view3d_get_view_aligned_coordinate(&vc, min, event->mval);
 | 
						|
		mul_m4_v3(vc.obedit->imat, min); // back in object space
 | 
						|
		
 | 
						|
		sub_v3_v3(min, cent);
 | 
						|
		
 | 
						|
		/* calculate rotation */
 | 
						|
		unit_m3(mat);
 | 
						|
		if(done) {
 | 
						|
			float dot;
 | 
						|
			
 | 
						|
			VECCOPY(vec, min);
 | 
						|
			normalize_v3(vec);
 | 
						|
			dot= INPR(vec, nor);
 | 
						|
 | 
						|
			if( fabs(dot)<0.999) {
 | 
						|
				float cross[3], si, q1[4];
 | 
						|
				
 | 
						|
				cross_v3_v3v3(cross, nor, vec);
 | 
						|
				normalize_v3(cross);
 | 
						|
				dot= 0.5f*saacos(dot);
 | 
						|
				
 | 
						|
				/* halve the rotation if its applied twice */
 | 
						|
				if(rot_src) dot *= 0.5f;
 | 
						|
				
 | 
						|
				si= (float)sin(dot);
 | 
						|
				q1[0]= (float)cos(dot);
 | 
						|
				q1[1]= cross[0]*si;
 | 
						|
				q1[2]= cross[1]*si;
 | 
						|
				q1[3]= cross[2]*si;				
 | 
						|
				quat_to_mat3( mat,q1);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		if(rot_src)
 | 
						|
			rotateflag(vc.em, SELECT, cent, mat);
 | 
						|
		
 | 
						|
		extrudeflag(vc.obedit, vc.em, SELECT, nor, 0);
 | 
						|
		rotateflag(vc.em, SELECT, cent, mat);
 | 
						|
		translateflag(vc.em, SELECT, min);
 | 
						|
		
 | 
						|
		recalc_editnormals(vc.em);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		float mat[3][3],imat[3][3];
 | 
						|
		float *curs= give_cursor(vc.scene, vc.v3d);
 | 
						|
		
 | 
						|
		VECCOPY(min, curs);
 | 
						|
		view3d_get_view_aligned_coordinate(&vc, min, event->mval);
 | 
						|
		
 | 
						|
		eve= addvertlist(vc.em, 0, NULL);
 | 
						|
 | 
						|
		copy_m3_m4(mat, vc.obedit->obmat);
 | 
						|
		invert_m3_m3(imat, mat);
 | 
						|
		
 | 
						|
		VECCOPY(eve->co, min);
 | 
						|
		mul_m3_v3(imat, eve->co);
 | 
						|
		sub_v3_v3v3(eve->co, eve->co, vc.obedit->obmat[3]);
 | 
						|
		
 | 
						|
		eve->f= SELECT;
 | 
						|
	}
 | 
						|
 | 
						|
	if(	((vc.scene->toolsettings->snap_flag & (SCE_SNAP|SCE_SNAP_PROJECT))==(SCE_SNAP|SCE_SNAP_PROJECT)) &&
 | 
						|
		(vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE)
 | 
						|
	) {
 | 
						|
		EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
 | 
						|
	}
 | 
						|
 | 
						|
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); 
 | 
						|
	DAG_id_flush_update(vc.obedit->data, OB_RECALC_DATA);
 | 
						|
	
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Duplicate or Extrude at 3D Cursor";
 | 
						|
	ot->description= "Duplicate and extrude selected vertices, edges or faces towards 3D Cursor";
 | 
						|
	ot->idname= "MESH_OT_dupli_extrude_cursor";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= dupli_extrude_cursor;
 | 
						|
	ot->poll= ED_operator_editmesh;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
 | 
						|
	RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ********************** */
 | 
						|
 | 
						|
/* selected faces get hidden edges */
 | 
						|
int make_fgon(EditMesh *em, wmOperator *op, int make)
 | 
						|
{
 | 
						|
	EditFace *efa;
 | 
						|
	EditEdge *eed;
 | 
						|
	EditVert *eve;
 | 
						|
	float *nor=NULL;	// reference
 | 
						|
	int done=0;
 | 
						|
	
 | 
						|
	if(make==0) {
 | 
						|
		for(efa= em->faces.first; efa; efa= efa->next) {
 | 
						|
			if(efa->f & SELECT) {
 | 
						|
				efa->fgonf= 0;
 | 
						|
				efa->e1->h &= ~EM_FGON;
 | 
						|
				efa->e2->h &= ~EM_FGON;
 | 
						|
				efa->e3->h &= ~EM_FGON;
 | 
						|
				if(efa->e4) efa->e4->h &= ~EM_FGON;
 | 
						|
				done= 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		EM_fgon_flags(em);	// redo flags and indices for fgons
 | 
						|
		
 | 
						|
		return done;
 | 
						|
	}
 | 
						|
 | 
						|
	/* tagging edges. rule is:
 | 
						|
	   - edge used by exactly 2 selected faces
 | 
						|
	   - no vertices allowed with only tagged edges (return)
 | 
						|
	   - face normals are allowed to difffer
 | 
						|
	 
 | 
						|
	*/
 | 
						|
	for(eed= em->edges.first; eed; eed= eed->next) {
 | 
						|
		eed->f1= 0;	// amount of selected
 | 
						|
		eed->f2= 0; // amount of unselected
 | 
						|
	}
 | 
						|
	
 | 
						|
	for(efa= em->faces.first; efa; efa= efa->next) {
 | 
						|
		if(efa->f & SELECT) {
 | 
						|
			if(nor==NULL) nor= efa->n;
 | 
						|
			if(efa->e1->f1 < 3) efa->e1->f1++;
 | 
						|
			if(efa->e2->f1 < 3) efa->e2->f1++;
 | 
						|
			if(efa->e3->f1 < 3) efa->e3->f1++;
 | 
						|
			if(efa->e4 && efa->e4->f1 < 3) efa->e4->f1++;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if(efa->e1->f2 < 3) efa->e1->f2++;
 | 
						|
			if(efa->e2->f2 < 3) efa->e2->f2++;
 | 
						|
			if(efa->e3->f2 < 3) efa->e3->f2++;
 | 
						|
			if(efa->e4 && efa->e4->f2 < 3) efa->e4->f2++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// now eed->f1 becomes tagged edge
 | 
						|
	for(eed= em->edges.first; eed; eed= eed->next) {
 | 
						|
		if(eed->f1==2 && eed->f2==0) eed->f1= 1;
 | 
						|
		else eed->f1= 0;
 | 
						|
	}
 | 
						|
	
 | 
						|
	// no vertices allowed with only tagged edges
 | 
						|
	for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
 | 
						|
	for(eed= em->edges.first; eed; eed= eed->next) {
 | 
						|
		if(eed->f1) {
 | 
						|
			eed->v1->f1 |= 1;
 | 
						|
			eed->v2->f1 |= 1;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			eed->v1->f1 |= 2;
 | 
						|
			eed->v2->f1 |= 2;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	for(eve= em->verts.first; eve; eve= eve->next) {
 | 
						|
		if(eve->f1==1) break;
 | 
						|
	}
 | 
						|
	if(eve) {
 | 
						|
		BKE_report(op->reports, RPT_ERROR, "Cannot make a polygon with interior vertices");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	
 | 
						|
	// check for faces
 | 
						|
	if(nor==NULL) {
 | 
						|
		BKE_report(op->reports, RPT_ERROR, "No faces were selected to make FGon");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	// and there we go
 | 
						|
	for(eed= em->edges.first; eed; eed= eed->next) {
 | 
						|
		if(eed->f1) {
 | 
						|
			eed->h |= EM_FGON;
 | 
						|
			done= 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	if(done)
 | 
						|
		EM_fgon_flags(em);	// redo flags and indices for fgons
 | 
						|
	return done;
 | 
						|
}
 | 
						|
 | 
						|
static int make_fgon_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	Object *obedit= CTX_data_edit_object(C);
 | 
						|
	EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
 | 
						|
 | 
						|
	if( make_fgon(em, op, 1) ) {
 | 
						|
		DAG_id_flush_update(obedit->data, OB_RECALC_DATA);	
 | 
						|
		WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 | 
						|
 | 
						|
		BKE_mesh_end_editmesh(obedit->data, em);
 | 
						|
		return OPERATOR_FINISHED;
 | 
						|
	}
 | 
						|
 | 
						|
	BKE_mesh_end_editmesh(obedit->data, em);
 | 
						|
	return OPERATOR_CANCELLED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_fgon_make(struct wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Make F-gon";
 | 
						|
	ot->description= "Make fgon from selected faces";
 | 
						|
	ot->idname= "MESH_OT_fgon_make";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->exec= make_fgon_exec;
 | 
						|
	ot->poll= ED_operator_editmesh;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
}
 | 
						|
 | 
						|
static int clear_fgon_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	Object *obedit= CTX_data_edit_object(C);
 | 
						|
	EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
 | 
						|
	
 | 
						|
	if( make_fgon(em, op, 0) ) {
 | 
						|
		DAG_id_flush_update(obedit->data, OB_RECALC_DATA);	
 | 
						|
		WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 | 
						|
		
 | 
						|
		BKE_mesh_end_editmesh(obedit->data, em);
 | 
						|
		return OPERATOR_FINISHED;
 | 
						|
	}
 | 
						|
 | 
						|
	BKE_mesh_end_editmesh(obedit->data, em);
 | 
						|
	return OPERATOR_CANCELLED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_fgon_clear(struct wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Clear F-gon";
 | 
						|
	ot->description= "Clear fgon from selected face";
 | 
						|
	ot->idname= "MESH_OT_fgon_clear";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->exec= clear_fgon_exec;
 | 
						|
	ot->poll= ED_operator_editmesh;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
}
 | 
						|
 | 
						|
/* precondition; 4 vertices selected, check for 4 edges and create face */
 | 
						|
static EditFace *addface_from_edges(EditMesh *em)
 | 
						|
{
 | 
						|
	EditEdge *eed, *eedar[4]={NULL, NULL, NULL, NULL};
 | 
						|
	EditVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL;
 | 
						|
	int a;
 | 
						|
	
 | 
						|
	/* find the 4 edges */
 | 
						|
	for(eed= em->edges.first; eed; eed= eed->next) {
 | 
						|
		if( (eed->f & SELECT) || (eed->v1->f & eed->v2->f & SELECT) ) {
 | 
						|
			if(eedar[0]==NULL) eedar[0]= eed;
 | 
						|
			else if(eedar[1]==NULL) eedar[1]= eed;
 | 
						|
			else if(eedar[2]==NULL) eedar[2]= eed;
 | 
						|
			else eedar[3]= eed;
 | 
						|
			
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	
 | 
						|
	if(eedar[3]) {
 | 
						|
		/* first 2 points */
 | 
						|
		v1= eedar[0]->v1;
 | 
						|
		v2= eedar[0]->v2;
 | 
						|
		
 | 
						|
		/* find the 2 edges connected to first edge */
 | 
						|
		for(a=1; a<4; a++) {
 | 
						|
			if( eedar[a]->v1 == v2) v3= eedar[a]->v2;
 | 
						|
			else if(eedar[a]->v2 == v2) v3= eedar[a]->v1;
 | 
						|
			else if( eedar[a]->v1 == v1) v4= eedar[a]->v2;
 | 
						|
			else if(eedar[a]->v2 == v1) v4= eedar[a]->v1;
 | 
						|
		}
 | 
						|
		
 | 
						|
		/* verify if last edge exists */
 | 
						|
		if(v3 && v4) {
 | 
						|
			for(a=1; a<4; a++) {
 | 
						|
				if( eedar[a]->v1==v3 && eedar[a]->v2==v4) break;
 | 
						|
				if( eedar[a]->v2==v3 && eedar[a]->v1==v4) break;
 | 
						|
			}
 | 
						|
			if(a!=4) {
 | 
						|
				return addfacelist(em, v1, v2, v3, v4, NULL, NULL);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* ******************************* */
 | 
						|
 | 
						|
/* this also allows to prevent triangles being made in quads */
 | 
						|
static int compareface_overlaps(EditFace *vl1, EditFace *vl2)
 | 
						|
{
 | 
						|
	EditVert *v1, *v2, *v3, *v4;
 | 
						|
	int equal= 0;
 | 
						|
	
 | 
						|
	v1= vl2->v1;
 | 
						|
	v2= vl2->v2;
 | 
						|
	v3= vl2->v3;
 | 
						|
	v4= vl2->v4;
 | 
						|
	
 | 
						|
	if(vl1==vl2) return 0;
 | 
						|
	
 | 
						|
	if(v4==NULL && vl1->v4==NULL) {
 | 
						|
		if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) equal++;
 | 
						|
		if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) equal++;
 | 
						|
		if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) equal++;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) equal++;
 | 
						|
		if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) equal++;
 | 
						|
		if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) equal++;
 | 
						|
		if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) equal++;
 | 
						|
	}
 | 
						|
 | 
						|
	if(v4 && vl1->v4) {
 | 
						|
		if(equal==4) return 1;
 | 
						|
	}
 | 
						|
	else 
 | 
						|
		if(equal>=3) return 1;
 | 
						|
	
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* checks for existence, and for tria overlapping inside quad */
 | 
						|
static EditFace *exist_face_overlaps(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
 | 
						|
{
 | 
						|
	EditFace *efa, efatest;
 | 
						|
	
 | 
						|
	efatest.v1= v1;
 | 
						|
	efatest.v2= v2;
 | 
						|
	efatest.v3= v3;
 | 
						|
	efatest.v4= v4;
 | 
						|
	
 | 
						|
	efa= em->faces.first;
 | 
						|
	while(efa) {
 | 
						|
		if(compareface_overlaps(&efatest, efa)) return efa;
 | 
						|
		efa= efa->next;
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* will be new face smooth or solid? depends on smoothness of face neighbours
 | 
						|
 * of new face, if function return 1, then new face will be smooth, when functio
 | 
						|
 * will return zero, then new face will be solid */
 | 
						|
static void fix_new_face(EditMesh *em, EditFace *eface)
 | 
						|
{
 | 
						|
	struct EditFace *efa;
 | 
						|
	struct EditEdge *eed=NULL;
 | 
						|
	struct EditVert *v1 = eface->v1, *v2 = eface->v2, *v3 = eface->v3, *v4 = eface->v4;
 | 
						|
	struct EditVert *ev1=NULL, *ev2=NULL;
 | 
						|
	short smooth=0; /* "total smoothnes" of faces in neighbourhood */
 | 
						|
	short coef;	/* "weight" of smoothness */
 | 
						|
	short count=0;	/* number of edges with same direction as eface */
 | 
						|
	short vi00=0, vi01=0, vi10=0, vi11=0; /* vertex indexes */
 | 
						|
 | 
						|
	efa = em->faces.first;
 | 
						|
 | 
						|
	while(efa) {
 | 
						|
 | 
						|
		if(efa==eface) {
 | 
						|
			efa = efa->next;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		coef = 0;
 | 
						|
		ev1 = ev2 = NULL;
 | 
						|
		eed = NULL;
 | 
						|
 | 
						|
		if(efa->v1==v1 || efa->v2==v1 || efa->v3==v1 || efa->v4==v1) {
 | 
						|
			ev1 = v1;
 | 
						|
			coef++;
 | 
						|
		}
 | 
						|
		if(efa->v1==v2 || efa->v2==v2 || efa->v3==v2 || efa->v4==v2) {
 | 
						|
			if(ev1) ev2 = v2;
 | 
						|
			else ev1 = v2;
 | 
						|
			coef++;
 | 
						|
		}
 | 
						|
		if(efa->v1==v3 || efa->v2==v3 || efa->v3==v3 || efa->v4==v3) {
 | 
						|
			if(coef<2) {
 | 
						|
				if(ev1) ev2 = v3;
 | 
						|
				else ev1 = v3;
 | 
						|
			}
 | 
						|
			coef++;
 | 
						|
		}
 | 
						|
		if((v4) && (efa->v1==v4 || efa->v2==v4 || efa->v3==v4 || efa->v4==v4)) {
 | 
						|
			if(ev1 && coef<2) ev2 = v4;
 | 
						|
			coef++;
 | 
						|
		}
 | 
						|
 | 
						|
		/* "democracy" of smoothness */
 | 
						|
		if(efa->flag & ME_SMOOTH)
 | 
						|
			smooth += coef;
 | 
						|
		else
 | 
						|
			smooth -= coef;
 | 
						|
 | 
						|
		/* try to find edge using vertexes ev1 and ev2 */
 | 
						|
		if((ev1) && (ev2) && (ev1!=ev2)) eed = findedgelist(em, ev1, ev2);
 | 
						|
 | 
						|
		/* has bordering edge of efa same direction as edge of eface ? */
 | 
						|
		if(eed) {
 | 
						|
			if(eed->v1==v1) vi00 = 1;
 | 
						|
			else if(eed->v1==v2) vi00 = 2;
 | 
						|
			else if(eed->v1==v3) vi00 = 3;
 | 
						|
			else if(v4 && eed->v1==v4) vi00 = 4;
 | 
						|
 | 
						|
			if(eed->v2==v1) vi01 = 1;
 | 
						|
			else if(eed->v2==v2) vi01 = 2;
 | 
						|
			else if(eed->v2==v3) vi01 = 3;
 | 
						|
			else if(v4 && eed->v2==v4) vi01 = 4;
 | 
						|
 | 
						|
			if(v4) {
 | 
						|
				if(vi01==1 && vi00==4) vi00 = 0;
 | 
						|
				if(vi01==4 && vi00==1) vi01 = 0;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if(vi01==1 && vi00==3) vi00 = 0;
 | 
						|
				if(vi01==3 && vi00==1) vi01 = 0;
 | 
						|
			}
 | 
						|
 | 
						|
			if(eed->v1==efa->v1) vi10 = 1;
 | 
						|
			else if(eed->v1==efa->v2) vi10 = 2;
 | 
						|
			else if(eed->v1==efa->v3) vi10 = 3;
 | 
						|
			else if(efa->v4 && eed->v1==efa->v4) vi10 = 4;
 | 
						|
 | 
						|
			if(eed->v2==efa->v1) vi11 = 1;
 | 
						|
			else if(eed->v2==efa->v2) vi11 = 2;
 | 
						|
			else if(eed->v2==efa->v3) vi11 = 3;
 | 
						|
			else if(efa->v4 && eed->v2==efa->v4) vi11 = 4;
 | 
						|
 | 
						|
			if(efa->v4) {
 | 
						|
				if(vi11==1 && vi10==4) vi10 = 0;
 | 
						|
				if(vi11==4 && vi10==1) vi11 = 0;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if(vi11==1 && vi10==3) vi10 = 0;
 | 
						|
				if(vi11==3 && vi10==1) vi11 = 0;
 | 
						|
			}
 | 
						|
 | 
						|
			if(((vi00>vi01) && (vi10>vi11)) ||
 | 
						|
				((vi00<vi01) && (vi10<vi11)))
 | 
						|
				count++;
 | 
						|
			else
 | 
						|
				count--;
 | 
						|
		}
 | 
						|
 | 
						|
		efa = efa->next;
 | 
						|
	}
 | 
						|
 | 
						|
	/* set up smoothness according voting of face in neighbourhood */
 | 
						|
	if(smooth >= 0)
 | 
						|
		eface->flag |= ME_SMOOTH;
 | 
						|
	else
 | 
						|
		eface->flag &= ~ME_SMOOTH;
 | 
						|
 | 
						|
	/* flip face, when too much "face normals" in neighbourhood is different */
 | 
						|
	if(count > 0) {
 | 
						|
		flipface(em, eface);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* only adds quads or trias when there's edges already */
 | 
						|
void addfaces_from_edgenet(EditMesh *em)
 | 
						|
{
 | 
						|
	EditVert *eve1, *eve2, *eve3, *eve4;
 | 
						|
	
 | 
						|
	for(eve1= em->verts.first; eve1; eve1= eve1->next) {
 | 
						|
		for(eve2= em->verts.first; (eve1->f & 1) && eve2; eve2= eve2->next) {
 | 
						|
			if(findedgelist(em, eve1,eve2)) {
 | 
						|
				for(eve3= em->verts.first; (eve2->f & 1) && eve3; eve3= eve3->next) {
 | 
						|
					if((eve2!=eve3 && (eve3->f & 1) && findedgelist(em, eve1,eve3))) {
 | 
						|
						EditEdge *sh_edge= NULL;
 | 
						|
						EditVert *sh_vert= NULL;
 | 
						|
						
 | 
						|
						sh_edge= findedgelist(em, eve2,eve3);
 | 
						|
						
 | 
						|
						if(sh_edge) { /* Add a triangle */
 | 
						|
							if(!exist_face_overlaps(em, eve1,eve2,eve3,NULL))
 | 
						|
								fix_new_face(em, addfacelist(em, eve1,eve2,eve3,NULL,NULL,NULL));
 | 
						|
						}
 | 
						|
						else { /* Check for a shared vertex */
 | 
						|
							for(eve4= em->verts.first; eve4; eve4= eve4->next) {
 | 
						|
								if(eve4!=eve1 && eve4!=eve2 && eve4!=eve3 && (eve4->f & 1) &&
 | 
						|
								   !findedgelist(em, eve1,eve4) && findedgelist(em, eve2,eve4) &&
 | 
						|
								   findedgelist(em, eve3,eve4)) {
 | 
						|
									sh_vert= eve4;
 | 
						|
									break;
 | 
						|
								}
 | 
						|
							}
 | 
						|
							
 | 
						|
							if(sh_vert) {
 | 
						|
								if(sh_vert) {
 | 
						|
									if(!exist_face_overlaps(em, eve1,eve2,eve4,eve3))
 | 
						|
										fix_new_face(em, addfacelist(em, eve1,eve2,eve4,eve3,NULL,NULL));
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	EM_select_flush(em);
 | 
						|
	
 | 
						|
// XXX	DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
 | 
						|
}
 | 
						|
 | 
						|
static void addedgeface_mesh(EditMesh *em, wmOperator *op)
 | 
						|
{
 | 
						|
	EditVert *eve, *neweve[4];
 | 
						|
	EditEdge *eed;
 | 
						|
	EditFace *efa;
 | 
						|
	short amount=0;
 | 
						|
 | 
						|
	/* how many selected ? */
 | 
						|
	if(em->selectmode & SCE_SELECT_EDGE) {
 | 
						|
		/* in edge mode finding selected vertices means flushing down edge codes... */
 | 
						|
		/* can't make face with only edge selection info... */
 | 
						|
		EM_selectmode_set(em);
 | 
						|
	}
 | 
						|
	
 | 
						|
	for(eve= em->verts.first; eve; eve= eve->next) {
 | 
						|
		if(eve->f & SELECT) {
 | 
						|
			amount++;
 | 
						|
			if(amount>4) break;			
 | 
						|
			neweve[amount-1]= eve;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if(amount==2) {
 | 
						|
		eed= addedgelist(em, neweve[0], neweve[1], NULL);
 | 
						|
		EM_select_edge(eed, 1);
 | 
						|
 | 
						|
		// XXX		DAG_id_flush_update(obedit->data, OB_RECALC_DATA);	
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	else if(amount > 4) {
 | 
						|
		addfaces_from_edgenet(em);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	else if(amount<2) {
 | 
						|
		BKE_report(op->reports, RPT_ERROR, "More vertices are needed to make an edge/face");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	efa= NULL; // check later
 | 
						|
 | 
						|
	if(amount==3) {
 | 
						|
		
 | 
						|
		if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], NULL)==0) {
 | 
						|
			efa= addfacelist(em, neweve[0], neweve[1], neweve[2], 0, NULL, NULL);
 | 
						|
			EM_select_face(efa, 1);
 | 
						|
		}
 | 
						|
		else BKE_report(op->reports, RPT_ERROR, "The selected vertices already form a face");
 | 
						|
	}
 | 
						|
	else if(amount==4) {
 | 
						|
		/* this test survives when theres 2 triangles */
 | 
						|
		if(exist_face(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
 | 
						|
			int tria= 0;
 | 
						|
			
 | 
						|
			/* remove trias if they exist, 4 cases.... */
 | 
						|
			if(exist_face(em, neweve[0], neweve[1], neweve[2], NULL)) tria++;
 | 
						|
			if(exist_face(em, neweve[0], neweve[1], neweve[3], NULL)) tria++;
 | 
						|
			if(exist_face(em, neweve[0], neweve[2], neweve[3], NULL)) tria++;
 | 
						|
			if(exist_face(em, neweve[1], neweve[2], neweve[3], NULL)) tria++;
 | 
						|
		
 | 
						|
			if(tria==2) join_triangles(em);
 | 
						|
			else if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
 | 
						|
				 /* If there are 4 Verts, But more selected edges, we need to call addfaces_from_edgenet */
 | 
						|
					EditEdge *eedcheck;
 | 
						|
					int count;
 | 
						|
					count = 0;
 | 
						|
					for(eedcheck= em->edges.first; eedcheck; eedcheck= eedcheck->next) {
 | 
						|
						if(eedcheck->f & SELECT) {
 | 
						|
							count++;
 | 
						|
						}
 | 
						|
					}	
 | 
						|
				
 | 
						|
				if(count++ > 4){
 | 
						|
					addfaces_from_edgenet(em);
 | 
						|
					return;
 | 
						|
				} else {
 | 
						|
				/* if 4 edges exist, we just create the face, convex or not */
 | 
						|
					efa= addface_from_edges(em);
 | 
						|
					if(efa==NULL) {
 | 
						|
						
 | 
						|
						/* the order of vertices can be anything, 6 cases to check */
 | 
						|
						if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
 | 
						|
							efa= addfacelist(em, neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
 | 
						|
						}
 | 
						|
						else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
 | 
						|
							efa= addfacelist(em, neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
 | 
						|
						}
 | 
						|
						else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
 | 
						|
							efa= addfacelist(em, neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
 | 
						|
						}
 | 
						|
						else if( convex(neweve[0]->co, neweve[1]->co, neweve[3]->co, neweve[2]->co) ) {
 | 
						|
							efa= addfacelist(em, neweve[0], neweve[1], neweve[3], neweve[2], NULL, NULL);
 | 
						|
						}
 | 
						|
						else if( convex(neweve[0]->co, neweve[3]->co, neweve[2]->co, neweve[1]->co) ) {
 | 
						|
							efa= addfacelist(em, neweve[0], neweve[3], neweve[2], neweve[1], NULL, NULL);
 | 
						|
						}
 | 
						|
						else if( convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co) ) {
 | 
						|
							efa= addfacelist(em, neweve[0], neweve[3], neweve[1], neweve[2], NULL, NULL);
 | 
						|
						}
 | 
						|
						else BKE_report(op->reports, RPT_ERROR, "cannot find nice quad from concave set of vertices");
 | 
						|
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else BKE_report(op->reports, RPT_ERROR, "The selected vertices already form a face");
 | 
						|
		}
 | 
						|
		else BKE_report(op->reports, RPT_ERROR, "The selected vertices already form a face");
 | 
						|
	}
 | 
						|
	
 | 
						|
	if(efa) {
 | 
						|
		EM_select_face(efa, 1);
 | 
						|
 | 
						|
		fix_new_face(em, efa);
 | 
						|
		
 | 
						|
		recalc_editnormals(em);
 | 
						|
	}
 | 
						|
	}
 | 
						|
 | 
						|
static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	Object *obedit= CTX_data_edit_object(C);
 | 
						|
	EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
 | 
						|
	
 | 
						|
	addedgeface_mesh(em, op);
 | 
						|
	
 | 
						|
	DAG_id_flush_update(obedit->data, OB_RECALC_DATA);	
 | 
						|
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 | 
						|
	
 | 
						|
	BKE_mesh_end_editmesh(obedit->data, em);
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_edge_face_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Make Edge/Face";
 | 
						|
	ot->description= "Add an edge or face to selected";
 | 
						|
	ot->idname= "MESH_OT_edge_face_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->exec= addedgeface_mesh_exec;
 | 
						|
	ot->poll= ED_operator_editmesh;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
	
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* ************************ primitives ******************* */
 | 
						|
 | 
						|
// HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker
 | 
						|
// this hack is only used so that scons+mingw + split-sources hack works
 | 
						|
	// ------------------------------- start copied code
 | 
						|
/* these are not the monkeys you are looking for */
 | 
						|
int monkeyo= 4;
 | 
						|
int monkeynv= 271;
 | 
						|
int monkeynf= 250;
 | 
						|
signed char monkeyv[271][3]= {
 | 
						|
{-71,21,98},{-63,12,88},{-57,7,74},{-82,-3,79},{-82,4,92},
 | 
						|
{-82,17,100},{-92,21,102},{-101,12,95},{-107,7,83},
 | 
						|
{-117,31,84},{-109,31,95},{-96,31,102},{-92,42,102},
 | 
						|
{-101,50,95},{-107,56,83},{-82,66,79},{-82,58,92},
 | 
						|
{-82,46,100},{-71,42,98},{-63,50,88},{-57,56,74},
 | 
						|
{-47,31,72},{-55,31,86},{-67,31,97},{-66,31,99},
 | 
						|
{-70,43,100},{-82,48,103},{-93,43,105},{-98,31,105},
 | 
						|
{-93,20,105},{-82,31,106},{-82,15,103},{-70,20,100},
 | 
						|
{-127,55,95},{-127,45,105},{-127,-87,94},{-127,-41,100},
 | 
						|
{-127,-24,102},{-127,-99,92},{-127,52,77},{-127,73,73},
 | 
						|
{-127,115,-70},{-127,72,-109},{-127,9,-106},{-127,-49,-45},
 | 
						|
{-101,-24,72},{-87,-56,73},{-82,-89,73},{-80,-114,68},
 | 
						|
{-85,-121,67},{-104,-124,71},{-127,-126,74},{-71,-18,68},
 | 
						|
{-46,-5,69},{-21,19,57},{-17,55,76},{-36,62,80},
 | 
						|
{-64,77,88},{-86,97,94},{-107,92,97},{-119,63,96},
 | 
						|
{-106,53,99},{-111,39,98},{-101,12,95},{-79,2,90},
 | 
						|
{-64,8,86},{-47,24,83},{-45,38,83},{-50,48,85},
 | 
						|
{-72,56,92},{-95,60,97},{-127,-98,94},{-113,-92,94},
 | 
						|
{-112,-107,91},{-119,-113,89},{-127,-114,88},{-127,-25,96},
 | 
						|
{-127,-18,95},{-114,-19,95},{-111,-29,96},{-116,-37,95},
 | 
						|
{-76,-6,86},{-48,7,80},{-34,26,77},{-32,48,84},
 | 
						|
{-39,53,93},{-71,70,102},{-87,82,107},{-101,79,109},
 | 
						|
{-114,55,108},{-111,-13,104},{-100,-57,91},{-95,-90,88},
 | 
						|
{-93,-105,85},{-97,-117,81},{-106,-119,81},{-127,-121,82},
 | 
						|
{-127,6,93},{-127,27,98},{-85,61,95},{-106,18,96},
 | 
						|
{-110,27,97},{-112,-88,94},{-117,-57,96},{-127,-57,96},
 | 
						|
{-127,-42,95},{-115,-35,100},{-110,-29,102},{-113,-17,100},
 | 
						|
{-122,-16,100},{-127,-26,106},{-121,-19,104},{-115,-20,104},
 | 
						|
{-113,-29,106},{-117,-32,103},{-127,-37,103},{-94,-40,71},
 | 
						|
{-106,-31,91},{-104,-40,91},{-97,-32,71},{-127,-112,88},
 | 
						|
{-121,-111,88},{-115,-105,91},{-115,-95,93},{-127,-100,84},
 | 
						|
{-115,-96,85},{-115,-104,82},{-121,-109,81},{-127,-110,81},
 | 
						|
{-105,28,100},{-103,20,99},{-84,55,97},{-92,54,99},
 | 
						|
{-73,51,99},{-55,45,89},{-52,37,88},{-53,25,87},
 | 
						|
{-66,13,92},{-79,8,95},{-98,14,100},{-104,38,100},
 | 
						|
{-100,48,100},{-97,46,97},{-102,38,97},{-96,16,97},
 | 
						|
{-79,11,93},{-68,15,90},{-57,27,86},{-56,36,86},
 | 
						|
{-59,43,87},{-74,50,96},{-91,51,98},{-84,52,96},
 | 
						|
{-101,22,96},{-102,29,96},{-113,59,78},{-102,85,79},
 | 
						|
{-84,88,76},{-65,71,71},{-40,58,63},{-25,52,59},
 | 
						|
{-28,21,48},{-50,0,53},{-71,-12,60},{-127,115,37},
 | 
						|
{-127,126,-10},{-127,-25,-86},{-127,-59,24},{-127,-125,59},
 | 
						|
{-127,-103,44},{-127,-73,41},{-127,-62,36},{-18,30,7},
 | 
						|
{-17,41,-6},{-28,34,-56},{-68,56,-90},{-33,-6,9},
 | 
						|
{-51,-16,-21},{-45,-1,-55},{-84,7,-85},{-97,-45,52},
 | 
						|
{-104,-53,33},{-90,-91,49},{-95,-64,50},{-85,-117,51},
 | 
						|
{-109,-97,47},{-111,-69,46},{-106,-121,56},{-99,-36,55},
 | 
						|
{-100,-29,60},{-101,-22,64},{-100,-50,21},{-89,-40,-34},
 | 
						|
{-83,-19,-69},{-69,111,-49},{-69,119,-9},{-69,109,30},
 | 
						|
{-68,67,55},{-34,52,43},{-46,58,36},{-45,90,7},
 | 
						|
{-25,72,16},{-25,79,-15},{-45,96,-25},{-45,87,-57},
 | 
						|
{-25,69,-46},{-48,42,-75},{-65,3,-70},{-22,42,-26},
 | 
						|
{-75,-22,19},{-72,-25,-27},{-13,52,-30},{-28,-18,-16},
 | 
						|
{6,-13,-42},{37,7,-55},{46,41,-54},{31,65,-54},
 | 
						|
{4,61,-40},{3,53,-37},{25,56,-50},{35,37,-52},
 | 
						|
{28,10,-52},{5,-5,-39},{-21,-9,-17},{-9,46,-28},
 | 
						|
{-6,39,-37},{-14,-3,-27},{6,0,-47},{25,12,-57},
 | 
						|
{31,32,-57},{23,46,-56},{4,44,-46},{-19,37,-27},
 | 
						|
{-20,22,-35},{-30,12,-35},{-22,11,-35},{-19,2,-35},
 | 
						|
{-23,-2,-35},{-34,0,-9},{-35,-3,-22},{-35,5,-24},
 | 
						|
{-25,26,-27},{-13,31,-34},{-13,30,-41},{-23,-2,-41},
 | 
						|
{-18,2,-41},{-21,10,-41},{-29,12,-41},{-19,22,-41},
 | 
						|
{6,42,-53},{25,44,-62},{34,31,-63},{28,11,-62},
 | 
						|
{7,0,-54},{-14,-2,-34},{-5,37,-44},{-13,14,-42},
 | 
						|
{-7,8,-43},{1,16,-47},{-4,22,-45},{3,30,-48},
 | 
						|
{8,24,-49},{15,27,-50},{12,35,-50},{4,56,-62},
 | 
						|
{33,60,-70},{48,38,-64},{41,7,-68},{6,-11,-63},
 | 
						|
{-26,-16,-42},{-17,49,-49},
 | 
						|
};
 | 
						|
 | 
						|
signed char monkeyf[250][4]= {
 | 
						|
{27,4,5,26}, {25,4,5,24}, {3,6,5,4}, {1,6,5,2}, {5,6,7,4}, 
 | 
						|
{3,6,7,2}, {5,8,7,6}, {3,8,7,4}, {7,8,9,6}, 
 | 
						|
{5,8,9,4}, {7,10,9,8}, {5,10,9,6}, {9,10,11,8}, 
 | 
						|
{7,10,11,6}, {9,12,11,10}, {7,12,11,8}, {11,6,13,12}, 
 | 
						|
{5,4,13,12}, {3,-2,13,12}, {-3,-4,13,12}, {-5,-10,13,12}, 
 | 
						|
{-11,-12,14,12}, {-13,-18,14,13}, {-19,4,5,13}, {10,12,4,4}, 
 | 
						|
{10,11,9,9}, {8,7,9,9}, {7,5,6,6}, {6,3,4,4}, 
 | 
						|
{5,1,2,2}, {4,-1,0,0}, {3,-3,-2,-2}, {22,67,68,23}, 
 | 
						|
{20,65,66,21}, {18,63,64,19}, {16,61,62,17}, {14,59,60,15}, 
 | 
						|
{12,19,48,57}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47}, 
 | 
						|
{18,19,48,47}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47}, 
 | 
						|
{18,19,48,47}, {18,-9,-8,47}, {18,27,45,46}, {26,55,43,44}, 
 | 
						|
{24,41,42,54}, {22,39,40,23}, {20,37,38,21}, {18,35,36,19}, 
 | 
						|
{16,33,34,17}, {14,31,32,15}, {12,39,30,13}, {11,48,45,38}, 
 | 
						|
{8,36,-19,9}, {8,-20,44,47}, {42,45,46,43}, {18,19,40,39}, 
 | 
						|
{16,17,38,37}, {14,15,36,35}, {32,44,43,33}, {12,33,32,42}, 
 | 
						|
{19,44,43,42}, {40,41,42,-27}, {8,9,39,-28}, {15,43,42,16}, 
 | 
						|
{13,43,42,14}, {11,43,42,12}, {9,-30,42,10}, {37,12,38,-32}, 
 | 
						|
{-33,37,45,46}, {-33,40,41,39}, {38,40,41,37}, {36,40,41,35}, 
 | 
						|
{34,40,41,33}, {36,39,38,37}, {35,40,39,38}, {1,2,14,21}, 
 | 
						|
{1,2,40,13}, {1,2,40,39}, {1,24,12,39}, {-34,36,38,11}, 
 | 
						|
{35,38,36,37}, {-37,8,35,37}, {-11,-12,-45,40}, {-11,-12,39,38}, 
 | 
						|
{-11,-12,37,36}, {-11,-12,35,34}, {33,34,40,41}, {33,34,38,39}, 
 | 
						|
{33,34,36,37}, {33,-52,34,35}, {33,37,36,34}, {33,35,34,34}, 
 | 
						|
{8,7,37,36}, {-32,7,35,46}, {-34,-33,45,46}, {4,-33,43,34}, 
 | 
						|
{-34,-33,41,42}, {-34,-33,39,40}, {-34,-33,37,38}, {-34,-33,35,36}, 
 | 
						|
{-34,-33,33,34}, {-34,-33,31,32}, {-34,-4,28,30}, {-5,-34,28,27}, 
 | 
						|
{-35,-44,36,27}, {26,35,36,45}, {24,25,44,45}, {25,23,44,42}, 
 | 
						|
{25,24,41,40}, {25,24,39,38}, {25,24,37,36}, {25,24,35,34}, 
 | 
						|
{25,24,33,32}, {25,24,31,30}, {15,24,29,38}, {25,24,27,26}, 
 | 
						|
{23,12,37,26}, {11,12,35,36}, {-86,-59,36,-80}, {-60,-61,36,35}, 
 | 
						|
{-62,-63,36,35}, {-64,-65,36,35}, {-66,-67,36,35}, {-68,-69,36,35}, 
 | 
						|
{-70,-71,36,35}, {-72,-73,36,35}, {-74,-75,36,35}, {42,43,53,58}, 
 | 
						|
{40,41,57,56}, {38,39,55,57}, {-81,-80,37,56}, {-83,-82,55,52}, 
 | 
						|
{-85,-84,51,49}, {-87,-86,48,49}, {47,50,51,48}, {46,48,51,49}, 
 | 
						|
{43,46,49,44}, {-92,-91,45,42}, {-23,49,50,-20}, {-94,40,48,-24}, 
 | 
						|
{-96,-22,48,49}, {-97,48,21,-90}, {-100,36,50,23}, {22,49,48,-100}, 
 | 
						|
{-101,47,46,22}, {21,45,35,25}, {33,34,44,41}, {13,14,28,24}, 
 | 
						|
{-107,26,30,-106}, {14,46,45,15}, {14,44,43,-110}, {-111,42,23,-110}, 
 | 
						|
{6,7,45,46}, {45,44,47,46}, {45,46,47,48}, {47,46,49,48}, 
 | 
						|
{17,49,47,48}, {17,36,46,48}, {35,36,44,45}, {35,36,40,43}, 
 | 
						|
{35,36,38,39}, {-4,-3,37,35}, {-123,34,33,1}, {-9,-8,-7,-6}, 
 | 
						|
{-10,-7,32,-125}, {-127,-11,-126,-126}, {-7,-6,5,31}, {4,5,33,30}, 
 | 
						|
{4,39,33,32}, {4,35,32,38}, {20,21,39,38}, {4,37,38,5}, 
 | 
						|
{-11,-10,36,3}, {-11,15,14,35}, {13,16,34,34}, {-13,14,13,13}, 
 | 
						|
{-3,1,30,29}, {-3,28,29,1}, {-2,31,28,-1}, {12,13,27,30}, 
 | 
						|
{-2,26,12,12}, {35,29,42,36}, {34,35,36,33}, {32,35,36,31}, 
 | 
						|
{30,35,36,29}, {28,35,36,27}, {26,35,36,25}, {34,39,38,35}, 
 | 
						|
{32,39,38,33}, {30,39,38,31}, {28,39,38,29}, {26,39,38,27}, 
 | 
						|
{25,31,32,38}, {-18,-17,45,44}, {-18,17,28,44}, {-24,-20,42,-23}, 
 | 
						|
{11,35,27,14}, {25,28,39,41}, {37,41,40,38}, {34,40,36,35}, 
 | 
						|
{32,40,39,33}, {30,39,31,40}, {21,29,39,22}, {-31,37,28,4}, 
 | 
						|
{-32,33,35,36}, {32,33,34,34}, {18,35,36,48}, {34,25,40,35}, 
 | 
						|
{24,25,38,39}, {24,25,36,37}, {24,25,34,35}, {24,25,32,33}, 
 | 
						|
{24,13,41,31}, {17,11,41,35}, {15,16,34,35}, {13,14,34,35}, 
 | 
						|
{11,12,34,35}, {9,10,34,35}, {7,8,34,35}, {26,25,37,36}, 
 | 
						|
{35,36,37,38}, {37,36,39,38}, {37,38,39,40}, {25,31,36,39}, 
 | 
						|
{18,34,35,30}, {17,22,30,33}, {19,29,21,20}, {16,26,29,17}, 
 | 
						|
{24,29,28,25}, {22,31,28,23}, {20,31,30,21}, {18,31,30,19}, 
 | 
						|
{16,30,17,17}, {-21,-22,35,34}, {-21,-22,33,32}, {-21,-22,31,30}, 
 | 
						|
{-21,-22,29,28}, {-21,-22,27,26}, {-28,-22,25,31}, {24,28,29,30}, 
 | 
						|
{23,24,26,27}, {23,24,25,25}, {-69,-35,-32,27}, {-70,26,25,-66}, 
 | 
						|
{-68,-67,24,-33}, 
 | 
						|
};
 | 
						|
	// ------------------------------- end copied code
 | 
						|
 | 
						|
 | 
						|
#define PRIM_PLANE		0
 | 
						|
#define PRIM_CUBE		1
 | 
						|
#define PRIM_CIRCLE		4
 | 
						|
#define PRIM_CYLINDER 	5
 | 
						|
#define PRIM_CONE 		7
 | 
						|
#define PRIM_GRID		10
 | 
						|
#define PRIM_UVSPHERE	11
 | 
						|
#define PRIM_ICOSPHERE 	12
 | 
						|
#define PRIM_MONKEY		13
 | 
						|
 | 
						|
static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int seg,
 | 
						|
		int subdiv, float dia, float depth, int ext, int fill)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	 * type - for the type of shape
 | 
						|
	 * dia - the radius for cone,sphere cylinder etc.
 | 
						|
	 * depth - 
 | 
						|
	 * ext - extrude
 | 
						|
	 * fill - end capping, and option to fill in circle
 | 
						|
	 * cent[3] - center of the data. 
 | 
						|
	 * */
 | 
						|
	EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
 | 
						|
	EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
 | 
						|
	float phi, phid, vec[3];
 | 
						|
	float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0};
 | 
						|
	short a, b;
 | 
						|
	
 | 
						|
	EM_clear_flag_all(em, SELECT);
 | 
						|
 | 
						|
	phid= 2.0f*(float)M_PI/tot;
 | 
						|
	phi= .25f*(float)M_PI;
 | 
						|
 | 
						|
	switch(type) {
 | 
						|
	case PRIM_GRID: /*  grid */
 | 
						|
		/* clear flags */
 | 
						|
		eve= em->verts.first;
 | 
						|
		while(eve) {
 | 
						|
			eve->f= 0;
 | 
						|
			eve= eve->next;
 | 
						|
		}
 | 
						|
		
 | 
						|
		/* one segment first: the X axis */		
 | 
						|
		phi = (2*dia)/(float)(tot-1);
 | 
						|
		phid = (2*dia)/(float)(seg-1);
 | 
						|
		for(a=0;a<tot;a++) {
 | 
						|
			vec[0] = (phi*a) - dia;
 | 
						|
			vec[1]= - dia;
 | 
						|
			vec[2]= 0.0f;
 | 
						|
			eve= addvertlist(em, vec, NULL);
 | 
						|
			eve->f= 1+2+4;
 | 
						|
			if (a) {
 | 
						|
				addedgelist(em, eve->prev, eve, NULL);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		/* extrude and translate */
 | 
						|
		vec[0]= vec[2]= 0.0;
 | 
						|
		vec[1]= phid;
 | 
						|
		
 | 
						|
		for(a=0;a<seg-1;a++) {
 | 
						|
			extrudeflag_vert(obedit, em, 2, nor, 0);	// nor unused
 | 
						|
			translateflag(em, 2, vec);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case PRIM_UVSPHERE: /*  UVsphere */
 | 
						|
		
 | 
						|
		/* clear all flags */
 | 
						|
		eve= em->verts.first;
 | 
						|
		while(eve) {
 | 
						|
			eve->f= 0;
 | 
						|
			eve= eve->next;
 | 
						|
		}
 | 
						|
		
 | 
						|
		/* one segment first */
 | 
						|
		phi= 0; 
 | 
						|
		phid/=2;
 | 
						|
		for(a=0; a<=tot; a++) {
 | 
						|
			vec[0]= dia*sin(phi);
 | 
						|
			vec[1]= 0.0;
 | 
						|
			vec[2]= dia*cos(phi);
 | 
						|
			eve= addvertlist(em, vec, NULL);
 | 
						|
			eve->f= 1+2+4;
 | 
						|
			if(a==0) v1= eve;
 | 
						|
			else addedgelist(em, 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;
 | 
						|
		quat_to_mat3( cmat,q);
 | 
						|
		
 | 
						|
		for(a=0; a<seg; a++) {
 | 
						|
			extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused
 | 
						|
			rotateflag(em, 2, v1->co, cmat);
 | 
						|
		}
 | 
						|
 | 
						|
		removedoublesflag(em, 4, 0, 0.0001);
 | 
						|
 | 
						|
		/* and now do imat */
 | 
						|
		eve= em->verts.first;
 | 
						|
		while(eve) {
 | 
						|
			if(eve->f & SELECT) {
 | 
						|
				mul_m4_v3(mat,eve->co);
 | 
						|
			}
 | 
						|
			eve= eve->next;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case PRIM_ICOSPHERE: /* Icosphere */
 | 
						|
		{
 | 
						|
			EditVert *eva[12];
 | 
						|
			EditEdge *eed;
 | 
						|
			
 | 
						|
			/* clear all flags */
 | 
						|
			eve= em->verts.first;
 | 
						|
			while(eve) {
 | 
						|
				eve->f= 0;
 | 
						|
				eve= eve->next;
 | 
						|
			}
 | 
						|
			dia/=200;
 | 
						|
			for(a=0;a<12;a++) {
 | 
						|
				vec[0]= dia*icovert[a][0];
 | 
						|
				vec[1]= dia*icovert[a][1];
 | 
						|
				vec[2]= dia*icovert[a][2];
 | 
						|
				eva[a]= addvertlist(em, vec, NULL);
 | 
						|
				eva[a]->f= 1+2;
 | 
						|
			}
 | 
						|
			for(a=0;a<20;a++) {
 | 
						|
				EditFace *evtemp;
 | 
						|
				v1= eva[ icoface[a][0] ];
 | 
						|
				v2= eva[ icoface[a][1] ];
 | 
						|
				v3= eva[ icoface[a][2] ];
 | 
						|
				evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL);
 | 
						|
				evtemp->e1->f = 1+2;
 | 
						|
				evtemp->e2->f = 1+2;
 | 
						|
				evtemp->e3->f = 1+2;
 | 
						|
			}
 | 
						|
 | 
						|
			dia*=200;
 | 
						|
			for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1, SUBDIV_CORNER_PATH, 0);
 | 
						|
			/* and now do imat */
 | 
						|
			eve= em->verts.first;
 | 
						|
			while(eve) {
 | 
						|
				if(eve->f & 2) {
 | 
						|
					mul_m4_v3(mat,eve->co);
 | 
						|
				}
 | 
						|
				eve= eve->next;
 | 
						|
			}
 | 
						|
			
 | 
						|
			// Clear the flag 2 from the edges
 | 
						|
			for(eed=em->edges.first;eed;eed=eed->next){
 | 
						|
				if(eed->f & 2){
 | 
						|
					   eed->f &= !2;
 | 
						|
				}   
 | 
						|
			}
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case PRIM_MONKEY: /* Monkey */
 | 
						|
		{
 | 
						|
			//extern int monkeyo, monkeynv, monkeynf;
 | 
						|
			//extern signed char monkeyf[][4];
 | 
						|
			//extern signed char monkeyv[][3];
 | 
						|
			EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
 | 
						|
			int i;
 | 
						|
 | 
						|
			for (i=0; i<monkeynv; i++) {
 | 
						|
				float v[3];
 | 
						|
				v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
 | 
						|
				tv[i]= addvertlist(em, v, NULL);
 | 
						|
				tv[i]->f |= SELECT;
 | 
						|
				tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL);
 | 
						|
				tv[monkeynv+i]->f |= SELECT;
 | 
						|
			}
 | 
						|
			for (i=0; i<monkeynf; i++) {
 | 
						|
				addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
 | 
						|
				addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
 | 
						|
			}
 | 
						|
 | 
						|
			MEM_freeN(tv);
 | 
						|
 | 
						|
			/* and now do imat */
 | 
						|
			for(eve= em->verts.first; eve; eve= eve->next) {
 | 
						|
				if(eve->f & SELECT) {
 | 
						|
					mul_m4_v3(mat,eve->co);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			recalc_editnormals(em);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	default: /* all types except grid, sphere... */
 | 
						|
		if(type==PRIM_CONE);
 | 
						|
		else if(ext==0) 
 | 
						|
			depth= 0.0f;
 | 
						|
	
 | 
						|
		/* vertices */
 | 
						|
		vtop= vdown= v1= v2= 0;
 | 
						|
		for(b=0; b<=ext; b++) {
 | 
						|
			for(a=0; a<tot; a++) {
 | 
						|
				
 | 
						|
				vec[0]= dia*sin(phi);
 | 
						|
				vec[1]= dia*cos(phi);
 | 
						|
				vec[2]= b?depth:-depth;
 | 
						|
				
 | 
						|
				mul_m4_v3(mat, vec);
 | 
						|
				eve= addvertlist(em, vec, NULL);
 | 
						|
				eve->f= SELECT;
 | 
						|
				if(a==0) {
 | 
						|
					if(b==0) v1= eve;
 | 
						|
					else v2= eve;
 | 
						|
				}
 | 
						|
				phi+=phid;
 | 
						|
			}
 | 
						|
		}
 | 
						|
			
 | 
						|
		/* center vertices */
 | 
						|
		/* type PRIM_CONE can only have 1 one side filled
 | 
						|
		 * if the cone has no capping, dont add vtop */
 | 
						|
		if(type == PRIM_CONE || (fill && !ELEM(type, PRIM_PLANE, PRIM_CUBE))) {
 | 
						|
			vec[0]= vec[1]= 0.0f;
 | 
						|
			vec[2]= type==PRIM_CONE ? depth : -depth;
 | 
						|
			mul_m4_v3(mat, vec);
 | 
						|
			vdown= addvertlist(em, vec, NULL);
 | 
						|
			if((ext || type==PRIM_CONE) && fill) {
 | 
						|
				vec[0]= vec[1]= 0.0f;
 | 
						|
				vec[2]= type==PRIM_CONE ? -depth : depth;
 | 
						|
				mul_m4_v3(mat,vec);
 | 
						|
				vtop= addvertlist(em, vec, NULL);
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			vdown= v1;
 | 
						|
			vtop= v2;
 | 
						|
		}
 | 
						|
		if(vtop) vtop->f= SELECT;
 | 
						|
		if(vdown) vdown->f= SELECT;
 | 
						|
	
 | 
						|
		/* top and bottom face */
 | 
						|
		if(fill || type==PRIM_CONE) {
 | 
						|
			if(tot==4 && ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
 | 
						|
				v3= v1->next->next;
 | 
						|
				if(ext) v4= v2->next->next;
 | 
						|
				
 | 
						|
				addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL);
 | 
						|
				if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL);
 | 
						|
				
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				v3= v1;
 | 
						|
				v4= v2;
 | 
						|
				for(a=1; a<tot; a++) {
 | 
						|
					addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL);
 | 
						|
					v3= v3->next;
 | 
						|
					if(ext && fill) {
 | 
						|
						addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL);
 | 
						|
						v4= v4->next;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				if(!ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
 | 
						|
					addfacelist(em, vdown, v3, v1, 0, NULL, NULL);
 | 
						|
					if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if(type==PRIM_CIRCLE) {  /* we need edges for a circle */
 | 
						|
			v3= v1;
 | 
						|
			for(a=1;a<tot;a++) {
 | 
						|
				addedgelist(em, v3, v3->next, NULL);
 | 
						|
				v3= v3->next;
 | 
						|
			}
 | 
						|
			addedgelist(em, v3, v1, NULL);
 | 
						|
		}
 | 
						|
		/* side faces */
 | 
						|
		if(ext) {
 | 
						|
			v3= v1;
 | 
						|
			v4= v2;
 | 
						|
			for(a=1; a<tot; a++) {
 | 
						|
				addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL);
 | 
						|
				v3= v3->next;
 | 
						|
				v4= v4->next;
 | 
						|
			}
 | 
						|
			addfacelist(em, v3, v1, v2, v4, NULL, NULL);
 | 
						|
		}
 | 
						|
		else if(fill && type==PRIM_CONE) {
 | 
						|
			/* add the bottom flat area of the cone
 | 
						|
			 * if capping is disabled dont bother */
 | 
						|
			v3= v1;
 | 
						|
			for(a=1; a<tot; a++) {
 | 
						|
				addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL);
 | 
						|
				v3= v3->next;
 | 
						|
			}
 | 
						|
			addfacelist(em, vtop, v1, v3, 0, NULL, NULL);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	EM_stats_update(em);
 | 
						|
	/* simple selection flush OK, based on fact it's a single model */
 | 
						|
	EM_select_flush(em); /* flushes vertex -> edge -> face selection */
 | 
						|
	
 | 
						|
	if(type!=PRIM_PLANE && type!=PRIM_MONKEY)
 | 
						|
		EM_recalc_normal_direction(em, 0, 0);	/* otherwise monkey has eyes in wrong direction */
 | 
						|
 | 
						|
	BKE_mesh_end_editmesh(obedit->data, em);
 | 
						|
}
 | 
						|
 | 
						|
/* ********* add primitive operators ************* */
 | 
						|
 | 
						|
static char *get_mesh_defname(int type)
 | 
						|
{
 | 
						|
	switch (type) {
 | 
						|
		case PRIM_PLANE: return "Plane";
 | 
						|
		case PRIM_CUBE: return "Cube";
 | 
						|
		case PRIM_CIRCLE: return "Circle";
 | 
						|
		case PRIM_CYLINDER: return "Cylinder";
 | 
						|
		case PRIM_CONE: return "Cone";
 | 
						|
		case PRIM_GRID: return "Grid";
 | 
						|
		case PRIM_UVSPHERE: return "Sphere";
 | 
						|
		case PRIM_ICOSPHERE: return "Icosphere";
 | 
						|
		case PRIM_MONKEY: return "Monkey";
 | 
						|
		default:
 | 
						|
			return "Mesh";
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void make_prim_ext(bContext *C, float *loc, float *rot, int enter_editmode, unsigned int layer, 
 | 
						|
		int type, int tot, int seg,
 | 
						|
		int subdiv, float dia, float depth, int ext, int fill)
 | 
						|
{
 | 
						|
	Object *obedit= CTX_data_edit_object(C);
 | 
						|
	int newob = 0;
 | 
						|
	float mat[4][4];
 | 
						|
	float scale;
 | 
						|
 | 
						|
	if(obedit==NULL || obedit->type!=OB_MESH) {
 | 
						|
		obedit= ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer);
 | 
						|
		
 | 
						|
		rename_id((ID *)obedit, get_mesh_defname(type));
 | 
						|
		rename_id((ID *)obedit->data, get_mesh_defname(type));
 | 
						|
		
 | 
						|
		/* create editmode */
 | 
						|
		ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
 | 
						|
		newob = 1;
 | 
						|
	}
 | 
						|
	else DAG_id_flush_update(&obedit->id, OB_RECALC_DATA);
 | 
						|
 | 
						|
	scale= ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
 | 
						|
 | 
						|
	dia *= scale;
 | 
						|
	depth *= scale * 0.5f;
 | 
						|
 | 
						|
	make_prim(obedit, type, mat, tot, seg, subdiv, dia, depth, ext, fill);
 | 
						|
 | 
						|
	DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
 | 
						|
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 | 
						|
 | 
						|
 | 
						|
	/* userdef */
 | 
						|
	if (newob && !enter_editmode) {
 | 
						|
		ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */
 | 
						|
	}
 | 
						|
	WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_plane_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	/* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_PLANE, 4, 0, 0, sqrt(2.0f), 0.0f, 0, 1);
 | 
						|
	return OPERATOR_FINISHED;	
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_plane_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Plane";
 | 
						|
	ot->description= "Construct a filled planar mesh with 4 vertices";
 | 
						|
	ot->idname= "MESH_OT_primitive_plane_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_plane_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_cube_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	/* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_CUBE, 4, 0, 0, sqrt(2.0f), 2.0f, 1, 1);
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_cube_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Cube";
 | 
						|
	ot->description= "Construct a cube mesh";
 | 
						|
	ot->idname= "MESH_OT_primitive_cube_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_cube_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_circle_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_CIRCLE, RNA_int_get(op->ptr, "vertices"), 0, 0,
 | 
						|
			RNA_float_get(op->ptr,"radius"), 0.0f, 0,
 | 
						|
			RNA_boolean_get(op->ptr, "fill"));
 | 
						|
 | 
						|
	return OPERATOR_FINISHED;	
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_circle_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Circle";
 | 
						|
	ot->description= "Construct a circle mesh";
 | 
						|
	ot->idname= "MESH_OT_primitive_circle_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_circle_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
	
 | 
						|
	/* props */
 | 
						|
	RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 3, 500);
 | 
						|
	RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
 | 
						|
	RNA_def_boolean(ot->srna, "fill", 0, "Fill", "");
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_CYLINDER, RNA_int_get(op->ptr, "vertices"), 0, 0,
 | 
						|
			RNA_float_get(op->ptr,"radius"),
 | 
						|
			RNA_float_get(op->ptr, "depth"), 1, 
 | 
						|
			RNA_boolean_get(op->ptr, "cap_ends"));
 | 
						|
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Cylinder";
 | 
						|
	ot->description= "Construct a cylinder mesh";
 | 
						|
	ot->idname= "MESH_OT_primitive_cylinder_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_cylinder_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
	
 | 
						|
	/* props */
 | 
						|
	RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
 | 
						|
	RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
 | 
						|
	RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
 | 
						|
	RNA_def_boolean(ot->srna, "cap_ends", 1, "Cap Ends", "");
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_cone_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_CONE, RNA_int_get(op->ptr, "vertices"), 0, 0,
 | 
						|
			RNA_float_get(op->ptr,"radius"), RNA_float_get(op->ptr, "depth"),
 | 
						|
			0, RNA_boolean_get(op->ptr, "cap_end"));
 | 
						|
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_cone_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Cone";
 | 
						|
	ot->description= "Construct a conic mesh (ends filled)";
 | 
						|
	ot->idname= "MESH_OT_primitive_cone_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_cone_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
	
 | 
						|
	/* props */
 | 
						|
	RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
 | 
						|
	RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
 | 
						|
	RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
 | 
						|
	RNA_def_boolean(ot->srna, "cap_end", 0, "Cap End", "");
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_grid_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_GRID, RNA_int_get(op->ptr, "x_subdivisions"),
 | 
						|
			RNA_int_get(op->ptr, "y_subdivisions"), 0,
 | 
						|
			RNA_float_get(op->ptr,"size"), 0.0f, 0, 1);
 | 
						|
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_grid_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Grid";
 | 
						|
	ot->description= "Construct a grid mesh";
 | 
						|
	ot->idname= "MESH_OT_primitive_grid_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_grid_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
	
 | 
						|
	/* props */
 | 
						|
	RNA_def_int(ot->srna, "x_subdivisions", 10, INT_MIN, INT_MAX, "X Subdivisions", "", 3, 1000);
 | 
						|
	RNA_def_int(ot->srna, "y_subdivisions", 10, INT_MIN, INT_MAX, "Y Subdivisions", "", 3, 1000);
 | 
						|
	RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, FLT_MAX);
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_MONKEY, 0, 0, 2, 0.0f, 0.0f, 0, 0);
 | 
						|
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Monkey";
 | 
						|
	ot->description= "Construct a Suzanne mesh";
 | 
						|
	ot->idname= "MESH_OT_primitive_monkey_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_monkey_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_UVSPHERE, RNA_int_get(op->ptr, "ring_count"),
 | 
						|
			RNA_int_get(op->ptr, "segments"), 0,
 | 
						|
			RNA_float_get(op->ptr,"size"), 0.0f, 0, 0);
 | 
						|
 | 
						|
	return OPERATOR_FINISHED;	
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add UV Sphere";
 | 
						|
	ot->description= "Construct a UV sphere mesh";
 | 
						|
	ot->idname= "MESH_OT_primitive_uv_sphere_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_uvsphere_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
	
 | 
						|
	/* props */
 | 
						|
	RNA_def_int(ot->srna, "segments", 32, INT_MIN, INT_MAX, "Segments", "", 3, 500);
 | 
						|
	RNA_def_int(ot->srna, "ring_count", 16, INT_MIN, INT_MAX, "Rings", "", 3, 500);
 | 
						|
	RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00);
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	int enter_editmode;
 | 
						|
	unsigned int layer;
 | 
						|
	float loc[3], rot[3];
 | 
						|
	
 | 
						|
	if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
 | 
						|
		return OPERATOR_CANCELLED;
 | 
						|
 | 
						|
	make_prim_ext(C, loc, rot, enter_editmode, layer,
 | 
						|
			PRIM_ICOSPHERE, 0, 0, RNA_int_get(op->ptr, "subdivisions"),
 | 
						|
			RNA_float_get(op->ptr,"size"), 0.0f, 0, 0);
 | 
						|
 | 
						|
	return OPERATOR_FINISHED;	
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Add Ico Sphere";
 | 
						|
	ot->description= "Construct an Icosphere mesh";
 | 
						|
	ot->idname= "MESH_OT_primitive_ico_sphere_add";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= ED_object_add_generic_invoke;
 | 
						|
	ot->exec= add_primitive_icosphere_exec;
 | 
						|
	ot->poll= ED_operator_scene_editable;
 | 
						|
	
 | 
						|
	/* flags */
 | 
						|
	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | 
						|
	
 | 
						|
	/* props */
 | 
						|
	RNA_def_int(ot->srna, "subdivisions", 2, 0, INT_MAX, "Subdivisions", "", 0, 8);
 | 
						|
	RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00);
 | 
						|
 | 
						|
	ED_object_add_generic_props(ot, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/****************** add duplicate operator ***************/
 | 
						|
 | 
						|
static int mesh_duplicate_exec(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
	Object *ob= CTX_data_edit_object(C);
 | 
						|
	EditMesh *em= BKE_mesh_get_editmesh(ob->data);
 | 
						|
 | 
						|
	adduplicateflag(em, SELECT);
 | 
						|
 | 
						|
	BKE_mesh_end_editmesh(ob->data, em);
 | 
						|
 | 
						|
	DAG_id_flush_update(ob->data, OB_RECALC_DATA);
 | 
						|
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
 | 
						|
	
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
 | 
						|
{
 | 
						|
	WM_cursor_wait(1);
 | 
						|
	mesh_duplicate_exec(C, op);
 | 
						|
	WM_cursor_wait(0);
 | 
						|
	
 | 
						|
	return OPERATOR_FINISHED;
 | 
						|
}
 | 
						|
 | 
						|
void MESH_OT_duplicate(wmOperatorType *ot)
 | 
						|
{
 | 
						|
	/* identifiers */
 | 
						|
	ot->name= "Duplicate";
 | 
						|
	ot->description= "Duplicate selected vertices, edges or faces";
 | 
						|
	ot->idname= "MESH_OT_duplicate";
 | 
						|
	
 | 
						|
	/* api callbacks */
 | 
						|
	ot->invoke= mesh_duplicate_invoke;
 | 
						|
	ot->exec= mesh_duplicate_exec;
 | 
						|
	
 | 
						|
	ot->poll= ED_operator_editmesh;
 | 
						|
	
 | 
						|
	/* to give to transform */
 | 
						|
	RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
 | 
						|
}
 | 
						|
 |