Пример #1
0
/**************************** registration **********************************/

void ED_operatortypes_mesh(void)
{
	WM_operatortype_append(MESH_OT_select_all);
	WM_operatortype_append(MESH_OT_select_interior_faces);
	WM_operatortype_append(MESH_OT_select_more);
	WM_operatortype_append(MESH_OT_select_less);
	WM_operatortype_append(MESH_OT_select_non_manifold);
	WM_operatortype_append(MESH_OT_select_linked);
	WM_operatortype_append(MESH_OT_select_linked_pick);
	WM_operatortype_append(MESH_OT_select_random);
	WM_operatortype_append(MESH_OT_hide);
	WM_operatortype_append(MESH_OT_reveal);
	WM_operatortype_append(MESH_OT_select_by_number_vertices);
	WM_operatortype_append(MESH_OT_select_loose_verts);
	WM_operatortype_append(MESH_OT_select_mirror);
	WM_operatortype_append(MESH_OT_normals_make_consistent);
	WM_operatortype_append(MESH_OT_merge);
	WM_operatortype_append(MESH_OT_subdivide);
	WM_operatortype_append(MESH_OT_faces_select_linked_flat);
	WM_operatortype_append(MESH_OT_edges_select_sharp);
	WM_operatortype_append(MESH_OT_primitive_plane_add);
	WM_operatortype_append(MESH_OT_primitive_cube_add);
	WM_operatortype_append(MESH_OT_primitive_circle_add);
	WM_operatortype_append(MESH_OT_primitive_cylinder_add);
	WM_operatortype_append(MESH_OT_primitive_cone_add);
	WM_operatortype_append(MESH_OT_primitive_grid_add);
	WM_operatortype_append(MESH_OT_primitive_monkey_add);
	WM_operatortype_append(MESH_OT_primitive_uv_sphere_add);
	WM_operatortype_append(MESH_OT_primitive_ico_sphere_add);
	WM_operatortype_append(MESH_OT_duplicate);
	WM_operatortype_append(MESH_OT_remove_doubles);
	WM_operatortype_append(MESH_OT_spin);
	WM_operatortype_append(MESH_OT_screw);

	WM_operatortype_append(MESH_OT_extrude_region);
	WM_operatortype_append(MESH_OT_extrude_faces_indiv);
	WM_operatortype_append(MESH_OT_extrude_edges_indiv);
	WM_operatortype_append(MESH_OT_extrude_verts_indiv);

	WM_operatortype_append(MESH_OT_split);
	WM_operatortype_append(MESH_OT_extrude_repeat);
	WM_operatortype_append(MESH_OT_edge_rotate);
	WM_operatortype_append(MESH_OT_select_vertex_path);
	WM_operatortype_append(MESH_OT_loop_to_region);
	WM_operatortype_append(MESH_OT_region_to_loop);
	WM_operatortype_append(MESH_OT_select_axis);
	
	WM_operatortype_append(MESH_OT_uvs_rotate);
	WM_operatortype_append(MESH_OT_uvs_reverse);
	WM_operatortype_append(MESH_OT_colors_rotate);
	WM_operatortype_append(MESH_OT_colors_reverse);
	
	WM_operatortype_append(MESH_OT_fill);
	WM_operatortype_append(MESH_OT_beautify_fill);
	WM_operatortype_append(MESH_OT_quads_convert_to_tris);
	WM_operatortype_append(MESH_OT_tris_convert_to_quads);
	WM_operatortype_append(MESH_OT_dissolve);
	WM_operatortype_append(MESH_OT_dissolve_limited);
	WM_operatortype_append(MESH_OT_faces_shade_smooth);
	WM_operatortype_append(MESH_OT_faces_shade_flat);
	WM_operatortype_append(MESH_OT_sort_elements);

	WM_operatortype_append(MESH_OT_delete);
	WM_operatortype_append(MESH_OT_edge_collapse);
	WM_operatortype_append(MESH_OT_edge_collapse_loop);

	WM_operatortype_append(MESH_OT_separate);
	WM_operatortype_append(MESH_OT_dupli_extrude_cursor);
	WM_operatortype_append(MESH_OT_loop_select);
	WM_operatortype_append(MESH_OT_edge_face_add);
	WM_operatortype_append(MESH_OT_select_shortest_path);
	WM_operatortype_append(MESH_OT_select_similar);
	WM_operatortype_append(MESH_OT_loop_multi_select);
	WM_operatortype_append(MESH_OT_mark_seam);
	WM_operatortype_append(MESH_OT_mark_sharp);
	WM_operatortype_append(MESH_OT_vertices_smooth);
	WM_operatortype_append(MESH_OT_noise);
	WM_operatortype_append(MESH_OT_flip_normals);
	//WM_operatortype_append(MESH_OT_knife_cut);
	WM_operatortype_append(MESH_OT_rip);
	WM_operatortype_append(MESH_OT_blend_from_shape);
	WM_operatortype_append(MESH_OT_shape_propagate_to_all);
	
	WM_operatortype_append(MESH_OT_uv_texture_add);
	WM_operatortype_append(MESH_OT_uv_texture_remove);
	WM_operatortype_append(MESH_OT_vertex_color_add);
	WM_operatortype_append(MESH_OT_vertex_color_remove);
	WM_operatortype_append(MESH_OT_sticky_add);
	WM_operatortype_append(MESH_OT_sticky_remove);
	WM_operatortype_append(MESH_OT_drop_named_image);

	WM_operatortype_append(MESH_OT_edgering_select);
	WM_operatortype_append(MESH_OT_loopcut);

	WM_operatortype_append(MESH_OT_solidify);
	WM_operatortype_append(MESH_OT_select_nth);
	WM_operatortype_append(MESH_OT_vert_connect);
	WM_operatortype_append(MESH_OT_vert_slide);
	WM_operatortype_append(MESH_OT_knife_tool);

	WM_operatortype_append(MESH_OT_bevel);

	WM_operatortype_append(MESH_OT_select_next_loop);

	WM_operatortype_append(MESH_OT_bridge_edge_loops);
	WM_operatortype_append(MESH_OT_inset);
	WM_operatortype_append(MESH_OT_wireframe);
	WM_operatortype_append(MESH_OT_edge_split);

	WM_operatortype_append(MESH_OT_convex_hull);

#ifdef WITH_GAMEENGINE
	WM_operatortype_append(MESH_OT_navmesh_make);
	WM_operatortype_append(MESH_OT_navmesh_face_copy);
	WM_operatortype_append(MESH_OT_navmesh_face_add);
	WM_operatortype_append(MESH_OT_navmesh_reset);
	WM_operatortype_append(MESH_OT_navmesh_clear);
#endif
}

#if 0 /* UNUSED, remove? */
static int ED_operator_editmesh_face_select(bContext *C)
{
	Object *obedit = CTX_data_edit_object(C);
	if (obedit && obedit->type == OB_MESH) {
		BMEditMesh *em = BMEdit_FromObject(obedit);
		if (em && em->selectmode & SCE_SELECT_FACE) {
			return 1;
		}
	}
	return 0;
}
Пример #2
0
int ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
{
	if (sima && (ED_space_image_show_render(sima) || ED_space_image_show_paint(sima)))
		return 0;

	if (obedit && obedit->type == OB_MESH) {
		struct BMEditMesh *em = BMEdit_FromObject(obedit);
		int ret;

		ret = EDBM_mtexpoly_check(em);

		return ret;
	}

	return 0;
}
Пример #3
0
static void make_prim_finish(bContext *C, int *state, int enter_editmode)
{
	Object *obedit = CTX_data_edit_object(C);
	BMEditMesh *em = BMEdit_FromObject(obedit);

	/* Primitive has all verts selected, use vert select flush
	 * to push this up to edges & faces. */
	EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);

	EDBM_update_generic(C, em, TRUE);

	/* userdef */
	if (*state && !enter_editmode) {
		ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */
	}
	WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
}
Пример #4
0
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
{
	Object *obedit = CTX_data_edit_object(C);
	uiBlock *block = uiLayoutGetBlock(layout);

	uiBlockSetHandleFunc(block, do_view3d_header_buttons, NULL);

	if (obedit && (obedit->type == OB_MESH)) {
		BMEditMesh *em = BMEdit_FromObject(obedit);
		uiLayout *row;

		row = uiLayoutRow(layout, TRUE);
		block = uiLayoutGetBlock(row);
		uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select - Shift-Click for multiple modes");
		uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select - Shift-Click for multiple modes");
		uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Face select - Shift-Click for multiple modes");
	}
}
Пример #5
0
static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
{
	wmWindow *win = CTX_wm_window(C);
	ToolSettings *ts = CTX_data_tool_settings(C);
	ScrArea *sa = CTX_wm_area(C);
	View3D *v3d = sa->spacedata.first;
	Object *obedit = CTX_data_edit_object(C);
	BMEditMesh *em = NULL;
	int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift;
	PointerRNA props_ptr;
	
	if (obedit && obedit->type == OB_MESH) {
		em = BMEdit_FromObject(obedit);
	}
	/* watch it: if sa->win does not exist, check that when calling direct drawing routines */

	switch (event) {
		case B_REDR:
			ED_area_tag_redraw(sa);
			break;

		case B_MODESELECT:
			WM_operator_properties_create(&props_ptr, "OBJECT_OT_mode_set");
			RNA_enum_set(&props_ptr, "mode", v3d->modeselect);
			WM_operator_name_call(C, "OBJECT_OT_mode_set", WM_OP_EXEC_REGION_WIN, &props_ptr);
			WM_operator_properties_free(&props_ptr);
			break;

		case B_SEL_VERT:
			if (em) {
				if (shift == 0 || em->selectmode == 0)
					em->selectmode = SCE_SELECT_VERTEX;
				ts->selectmode = em->selectmode;
				EDBM_selectmode_set(em);
				WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
				ED_undo_push(C, "Selectmode Set: Vertex");
			}
			break;
		case B_SEL_EDGE:
			if (em) {
				if (shift == 0 || em->selectmode == 0) {
					if ( (em->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX) {
						if (ctrl) EDBM_selectmode_convert(em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
					}
					em->selectmode = SCE_SELECT_EDGE;
				}
				ts->selectmode = em->selectmode;
				EDBM_selectmode_set(em);
				WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
				ED_undo_push(C, "Selectmode Set: Edge");
			}
			break;
		case B_SEL_FACE:
			if (em) {
				if (shift == 0 || em->selectmode == 0) {
					if ( ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)) {
						if (ctrl) EDBM_selectmode_convert(em, (ts->selectmode ^ SCE_SELECT_FACE), SCE_SELECT_FACE);
					}
					em->selectmode = SCE_SELECT_FACE;
				}
				ts->selectmode = em->selectmode;
				EDBM_selectmode_set(em);
				WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
				ED_undo_push(C, "Selectmode Set: Face");
			}
			break;

		case B_MAN_TRANS:
			if (shift == 0 || v3d->twtype == 0) {
				v3d->twtype = V3D_MANIP_TRANSLATE;
			}
			ED_area_tag_redraw(sa);
			break;
		case B_MAN_ROT:
			if (shift == 0 || v3d->twtype == 0) {
				v3d->twtype = V3D_MANIP_ROTATE;
			}
			ED_area_tag_redraw(sa);
			break;
		case B_MAN_SCALE:
			if (shift == 0 || v3d->twtype == 0) {
				v3d->twtype = V3D_MANIP_SCALE;
			}
			ED_area_tag_redraw(sa);
			break;
		case B_NDOF:
			ED_area_tag_redraw(sa);
			break;
		case B_MAN_MODE:
			ED_area_tag_redraw(sa);
			break;
		default:
			break;
	}
}
Пример #6
0
void ED_object_enter_editmode(bContext *C, int flag)
{
	Scene *scene= CTX_data_scene(C);
	Base *base= NULL;
	Object *ob;
	ScrArea *sa= CTX_wm_area(C);
	View3D *v3d= NULL;
	int ok= 0;
	
	if (scene->id.lib) return;
	
	if (sa && sa->spacetype==SPACE_VIEW3D)
		v3d= sa->spacedata.first;
	
	if ((flag & EM_IGNORE_LAYER)==0) {
		base= CTX_data_active_base(C); /* active layer checked here for view3d */

		if (base==NULL) return;
		else if (v3d && (base->lay & v3d->lay)==0) return;
		else if (!v3d && (base->lay & scene->lay)==0) return;
	}
	else {
		base= scene->basact;
	}

	if (ELEM3(NULL, base, base->object, base->object->data)) return;

	ob = base->object;
	
	if (object_data_is_libdata(ob)) {
		error_libdata();
		return;
	}
	
	if (flag & EM_WAITCURSOR) waitcursor(1);

	ob->restore_mode = ob->mode;

	/* note, when switching scenes the object can have editmode data but
	 * not be scene->obedit: bug 22954, this avoids calling self eternally */
	if ((ob->restore_mode & OB_MODE_EDIT)==0)
		ED_object_toggle_modes(C, ob->mode);

	ob->mode= OB_MODE_EDIT;
	
	if (ob->type==OB_MESH) {
		BMEditMesh *em;
		ok= 1;
		scene->obedit = ob;  /* context sees this */

		EDBM_mesh_make(CTX_data_tool_settings(C), scene, ob);

		em = BMEdit_FromObject(ob);
		if (LIKELY(em)) {
			/* order doesn't matter */
			EDBM_mesh_normals_update(em);
			BMEdit_RecalcTessellation(em);
			
			BM_mesh_select_mode_flush(em->bm);
		}

		WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene);
	}
	else if (ob->type==OB_ARMATURE) {
		bArmature *arm= base->object->data;
		if (!arm) return;
		/*
		 * The function object_data_is_libdata make a problem here, the
		 * check for ob->proxy return 0 and let blender enter to edit mode
		 * this causes a crash when you try leave the edit mode.
		 * The problem is that i can't remove the ob->proxy check from
		 * object_data_is_libdata that prevent the bugfix #6614, so
		 * i add this little hack here.
		 */
		if (arm->id.lib) {
			error_libdata();
			return;
		}
		ok=1;
		scene->obedit= ob;
		ED_armature_to_edit(ob);
		/* to ensure all goes in restposition and without striding */
		DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME); // XXX: should this be OB_RECALC_DATA?

		WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_ARMATURE, scene);
	}
	else if (ob->type==OB_FONT) {
		scene->obedit= ob; // XXX for context
		ok= 1;
		make_editText(ob);

		WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_TEXT, scene);
	}
	else if (ob->type==OB_MBALL) {
		scene->obedit= ob; // XXX for context
		ok= 1;
		make_editMball(ob);

		WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MBALL, scene);
	}
	else if (ob->type==OB_LATTICE) {
		scene->obedit= ob; // XXX for context
		ok= 1;
		make_editLatt(ob);
		
		WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_LATTICE, scene);
	}
	else if (ob->type==OB_SURF || ob->type==OB_CURVE) {
		ok= 1;
		scene->obedit= ob; // XXX for context
		make_editNurb(ob);
		
		WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_CURVE, scene);
	}
	
	if (ok) {
		DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	}
	else {
		scene->obedit= NULL; // XXX for context
		ob->mode &= ~OB_MODE_EDIT;
		WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, scene);
	}
	
	if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode");
	if (flag & EM_WAITCURSOR) waitcursor(0);
}
Пример #7
0
static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR],
                             int level, short flag)
{
	Object *ob, *ob_iter;
	Mesh *me = par->data;
	Base *base = NULL;
	DerivedMesh *dm;
	VertexDupliData vdd;
	Scene *sce = NULL;
	Group *group = NULL;
	GroupObject *go = NULL;
	BMEditMesh *em;
	float vec[3], no[3], pmat[4][4];
	int totvert, a, oblay;
	unsigned int lay;
	
	copy_m4_m4(pmat, par->obmat);
	
	/* simple preventing of too deep nested groups */
	if (level > MAX_DUPLI_RECUR) return;
	
	em = BMEdit_FromObject(par);
	
	if (em) {
		dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
	}
	else
		dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
	
	if (flag & DUPLILIST_FOR_RENDER) {
		vdd.orco = (float(*)[3])BKE_mesh_orco_verts_get(par);
		BKE_mesh_orco_verts_transform(me, vdd.orco, me->totvert, 0);
	}
	else
		vdd.orco = NULL;
	
	totvert = dm->getNumVerts(dm);

	/* having to loop on scene OR group objects is NOT FUN */
	if (GS(id->name) == ID_SCE) {
		sce = (Scene *)id;
		lay = sce->lay;
		base = sce->base.first;
	}
	else {
		group = (Group *)id;
		lay = group->layer;
		go = group->gobject.first;
	}
	
	/* Start looping on Scene OR Group objects */
	while (base || go) {
		if (sce) {
			ob_iter = base->object;
			oblay = base->lay;
		}
		else {
			ob_iter = go->ob;
			oblay = ob_iter->lay;
		}
		
		if (lay & oblay && scene->obedit != ob_iter) {
			ob = ob_iter->parent;
			while (ob) {
				if (ob == par) {
					ob = ob_iter;
					/* End Scene/Group object loop, below is generic */
					
					
					/* par_space_mat - only used for groups so we can modify the space dupli's are in
					 * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat
					 */
					if (par_space_mat)
						mult_m4_m4m4(vdd.obmat, par_space_mat, ob->obmat);
					else
						copy_m4_m4(vdd.obmat, ob->obmat);

					vdd.id = id;
					vdd.level = level;
					vdd.flag = flag;
					vdd.lb = lb;
					vdd.ob = ob;
					vdd.scene = scene;
					vdd.par = par;
					copy_m4_m4(vdd.pmat, pmat);
					vdd.persistent_id = persistent_id;
					
					/* mballs have a different dupli handling */
					if (ob->type != OB_MBALL) ob->flag |= OB_DONE;  /* doesnt render */

					if (me->edit_btmesh) {
						dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void *) &vdd);
					}
					else {
						for (a = 0; a < totvert; a++) {
							dm->getVertCo(dm, a, vec);
							dm->getVertNo(dm, a, no);
							
							vertex_dupli__mapFunc(&vdd, a, vec, no, NULL);
						}
					}
					if (sce) {
						/* Set proper layer in case of scene looping,
						 * in case of groups the object layer will be
						 * changed when it's duplicated due to the
						 * group duplication.
						 */
						ob->lay = vdd.par->lay;
					}
					
					break;
				}
				ob = ob->parent;
			}
		}
		if (sce) base = base->next;     /* scene loop */
		else go = go->next;             /* group loop */
	}

	if (vdd.orco)
		MEM_freeN(vdd.orco);
	dm->release(dm);
}
Пример #8
0
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR],
                           int level, short flag)
{
	Object *ob, *ob_iter;
	Base *base = NULL;
	DupliObject *dob;
	DerivedMesh *dm;
	Mesh *me = par->data;
	MLoopUV *mloopuv;
	MPoly *mpoly, *mp;
	MLoop *mloop;
	MVert *mvert;
	float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w;
	int lay, oblay, totface, a;
	Scene *sce = NULL;
	Group *group = NULL;
	GroupObject *go = NULL;
	BMEditMesh *em;
	float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
	
	/* simple preventing of too deep nested groups */
	if (level > MAX_DUPLI_RECUR) return;
	
	copy_m4_m4(pmat, par->obmat);
	em = BMEdit_FromObject(par);

	if (em) {
		dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
	}
	else {
		dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
	}

	totface = dm->getNumPolys(dm);
	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);
	mvert = dm->getVertArray(dm);

	if (flag & DUPLILIST_FOR_RENDER) {
		orco = (float(*)[3])BKE_mesh_orco_verts_get(par);
		BKE_mesh_orco_verts_transform(me, orco, me->totvert, 0);
		mloopuv = me->mloopuv;
	}
	else {
		orco = NULL;
		mloopuv = NULL;
	}
	
	/* having to loop on scene OR group objects is NOT FUN */
	if (GS(id->name) == ID_SCE) {
		sce = (Scene *)id;
		lay = sce->lay;
		base = sce->base.first;
	}
	else {
		group = (Group *)id;
		lay = group->layer;
		go = group->gobject.first;
	}
	
	/* Start looping on Scene OR Group objects */
	while (base || go) {
		if (sce) {
			ob_iter = base->object;
			oblay = base->lay;
		}
		else {
			ob_iter = go->ob;
			oblay = ob_iter->lay;
		}
		
		if (lay & oblay && scene->obedit != ob_iter) {
			ob = ob_iter->parent;
			while (ob) {
				if (ob == par) {
					ob = ob_iter;
					/* End Scene/Group object loop, below is generic */
					
					/* par_space_mat - only used for groups so we can modify the space dupli's are in
					 * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat
					 */
					if (par_space_mat)
						mult_m4_m4m4(ob__obmat, par_space_mat, ob->obmat);
					else
						copy_m4_m4(ob__obmat, ob->obmat);
					
					copy_m3_m4(imat, ob->parentinv);
						
					/* mballs have a different dupli handling */
					if (ob->type != OB_MBALL) ob->flag |= OB_DONE;  /* doesnt render */

					for (a = 0, mp = mpoly; a < totface; a++, mp++) {
						int mv1;
						int mv2;
						int mv3;
						/* int mv4; */ /* UNUSED */
						float *v1;
						float *v2;
						float *v3;
						/* float *v4; */ /* UNUSED */
						float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
						float f_no[3];
						MLoop *loopstart = mloop + mp->loopstart;

						if (UNLIKELY(mp->totloop < 3)) {
							continue;
						}
						else {
							BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mvert, f_no);
							v1 = mvert[(mv1 = loopstart[0].v)].co;
							v2 = mvert[(mv2 = loopstart[1].v)].co;
							v3 = mvert[(mv3 = loopstart[2].v)].co;
						}

						/* translation */
						BKE_mesh_calc_poly_center(mp, loopstart, mvert, cent);

						mul_m4_v3(pmat, cent);
						
						sub_v3_v3v3(cent, cent, pmat[3]);
						add_v3_v3(cent, ob__obmat[3]);
						
						copy_m4_m4(obmat, ob__obmat);
						
						copy_v3_v3(obmat[3], cent);
						
						/* rotation */
						tri_to_quat_ex(quat, v1, v2, v3, f_no);
						quat_to_mat3(mat, quat);
						
						/* scale */
						if (par->transflag & OB_DUPLIFACES_SCALE) {
							float size = BKE_mesh_calc_poly_area(mp, loopstart, mvert, f_no);
							size = sqrtf(size) * par->dupfacesca;
							mul_m3_fl(mat, size);
						}
						
						copy_m3_m3(mat3, mat);
						mul_m3_m3m3(mat, imat, mat3);
						
						copy_m4_m4(tmat, obmat);
						mul_m4_m4m3(obmat, tmat, mat);
						
						dob = new_dupli_object(lb, ob, obmat, par->lay, persistent_id, level, a, OB_DUPLIFACES, (flag & DUPLILIST_ANIMATED));
						if (flag & DUPLILIST_FOR_RENDER) {
							w = 1.0f / (float)mp->totloop;

							if (orco) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
								}
							}

							if (mloopuv) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w);
								}
							}
						}
						
						if (ob->transflag & OB_DUPLI) {
							float tmpmat[4][4];
							copy_m4_m4(tmpmat, ob->obmat);
							copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */
							object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, persistent_id, level + 1, a, flag);
							copy_m4_m4(ob->obmat, tmpmat);
						}
					}
					
					break;
				}
				ob = ob->parent;
			}
		}
		if (sce) base = base->next;     /* scene loop */
		else go = go->next;             /* group loop */
	}

	if (orco)
		MEM_freeN(orco);
	
	dm->release(dm);
}