示例#1
0
static int connect_hair_exec(bContext *C, wmOperator *op)
{
	Scene *scene= CTX_data_scene(C);
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
	ParticleSystem *psys= NULL;
	int all = RNA_boolean_get(op->ptr, "all");

	if(!ob)
		return OPERATOR_CANCELLED;

	if(all) {
		for(psys=ob->particlesystem.first; psys; psys=psys->next) {
			connect_hair(scene, ob, psys);
		}
	}
	else {
		psys = ptr.data;
		connect_hair(scene, ob, psys);
	}

	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);

	return OPERATOR_FINISHED;
}
static int remove_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
{
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
	ParticleSystem *psys= ptr.data;
	ParticleSettings *part;
	ParticleDupliWeight *dw;

	if (!psys)
		return OPERATOR_CANCELLED;

	part = psys->part;
	for (dw=part->dupliweights.first; dw; dw=dw->next) {
		if (dw->flag & PART_DUPLIW_CURRENT) {
			BLI_remlink(&part->dupliweights, dw);
			MEM_freeN(dw);
			break;
		}

	}
	dw = part->dupliweights.last;

	if (dw)
		dw->flag |= PART_DUPLIW_CURRENT;

	WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
	
	return OPERATOR_FINISHED;
}
static int remove_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
{
	Main *bmain = CTX_data_main(C);
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
	ParticleSystem *psys= ptr.data;
	Object *ob = ptr.id.data;

	ParticleTarget *pt;

	if (!psys)
		return OPERATOR_CANCELLED;

	pt = psys->targets.first;
	for (; pt; pt=pt->next) {
		if (pt->flag & PTARGET_CURRENT) {
			BLI_remlink(&psys->targets, pt);
			MEM_freeN(pt);
			break;
		}

	}
	pt = psys->targets.last;

	if (pt)
		pt->flag |= PTARGET_CURRENT;

	DAG_relations_tag_update(bmain);
	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);

	WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
	
	return OPERATOR_FINISHED;
}
static int new_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
{
	Main *bmain = CTX_data_main(C);
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
	ParticleSystem *psys= ptr.data;
	Object *ob = ptr.id.data;

	ParticleTarget *pt;

	if (!psys)
		return OPERATOR_CANCELLED;

	pt = psys->targets.first;
	for (; pt; pt=pt->next)
		pt->flag &= ~PTARGET_CURRENT;

	pt = MEM_callocN(sizeof(ParticleTarget), "keyed particle target");

	pt->flag |= PTARGET_CURRENT;
	pt->psys = 1;

	BLI_addtail(&psys->targets, pt);

	DAG_relations_tag_update(bmain);
	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);

	WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
	
	return OPERATOR_FINISHED;
}
static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op))
{
	Main *bmain= CTX_data_main(C);
	ParticleSystem *psys;
	ParticleSettings *part = NULL;
	Object *ob;
	PointerRNA ptr;

	ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);

	psys = ptr.data;

	/* add or copy particle setting */
	if (psys->part)
		part= BKE_particlesettings_copy(psys->part);
	else
		part= psys_new_settings("ParticleSettings", bmain);

	ob= ptr.id.data;

	if (psys->part)
		psys->part->id.us--;

	psys->part = part;

	psys_check_boid_data(psys);

	DAG_relations_tag_update(bmain);
	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);

	WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
	
	return OPERATOR_FINISHED;
}
示例#6
0
static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all)
{
	PTCacheBaker *baker = MEM_callocN(sizeof(PTCacheBaker), "PTCacheBaker");

	baker->main = CTX_data_main(C);
	baker->scene = CTX_data_scene(C);
	baker->bake = RNA_boolean_get(op->ptr, "bake");
	baker->render = 0;
	baker->anim_init = 0;
	baker->quick_step = 1;

	if (!all) {
		PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
		Object *ob = ptr.id.data;
		PointCache *cache = ptr.data;

		ListBase pidlist;
		BKE_ptcache_ids_from_object(&pidlist, ob, baker->scene, MAX_DUPLI_RECUR);

		for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
			if (pid->cache == cache) {
				baker->pid = *pid;
				break;
			}
		}

		BLI_freelistN(&pidlist);
	}

	return baker;
}
static int connect_hair_exec(bContext *C, wmOperator *op)
{
	Scene *scene= CTX_data_scene(C);
	Object *ob= ED_object_context(C);
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
	ParticleSystem *psys= NULL;
	const bool all = RNA_boolean_get(op->ptr, "all");
	bool any_connected = false;

	if (!ob)
		return OPERATOR_CANCELLED;

	if (all) {
		for (psys=ob->particlesystem.first; psys; psys=psys->next) {
			any_connected |= connect_hair(scene, ob, psys);
		}
	}
	else {
		psys = ptr.data;
		any_connected |= connect_hair(scene, ob, psys);
	}

	if (!any_connected) {
		BKE_report(op->reports, RPT_ERROR, "Can't disconnect hair if particle system modifier is disabled");
		return OPERATOR_CANCELLED;
	}

	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);

	return OPERATOR_FINISHED;
}
示例#8
0
static int ptcache_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
	PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
	Scene *scene= CTX_data_scene(C);
	Object *ob= ptr.id.data;
	PointCache *cache= ptr.data;
	PTCacheID *pid;
	ListBase pidlist;

	BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
	
	for(pid=pidlist.first; pid; pid=pid->next) {
		if(pid->cache == cache) {
			if(pid->ptcaches->first == pid->ptcaches->last)
				continue; /* don't delete last cache */

			BLI_remlink(pid->ptcaches, pid->cache);
			BKE_ptcache_free(pid->cache);
			*(pid->cache_ptr) = pid->ptcaches->first;

			break;
		}
	}

	BLI_freelistN(&pidlist);
	
	WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);

	return OPERATOR_FINISHED;
}
示例#9
0
static int vertex_group_menu_exec(bContext *C, wmOperator *op)
{
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
	uiPopupMenu *pup;
	uiLayout *layout;

	pup= uiPupMenuBegin(C, "Vertex Groups", 0);
	layout= uiPupMenuLayout(pup);
	uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);

	if(vgroup_object_in_edit_mode(ob)) {
		uiItemBooleanO(layout, "Assign to New Group", 0, "OBJECT_OT_vertex_group_assign", "new", 1);

		if(BLI_countlist(&ob->defbase) && ob->actdef) {
			uiItemO(layout, "Assign to Group", 0, "OBJECT_OT_vertex_group_assign");
			uiItemO(layout, "Remove from Group", 0, "OBJECT_OT_vertex_group_remove_from");
			uiItemBooleanO(layout, "Remove from All", 0, "OBJECT_OT_vertex_group_remove_from", "all", 1);
		}
	}

	if(BLI_countlist(&ob->defbase) && ob->actdef) {
		if(vgroup_object_in_edit_mode(ob))
			uiItemS(layout);

		uiItemO(layout, "Set Active Group", 0, "OBJECT_OT_vertex_group_set_active");
		uiItemO(layout, "Remove Group", 0, "OBJECT_OT_vertex_group_remove");
		uiItemBooleanO(layout, "Remove All Groups", 0, "OBJECT_OT_vertex_group_remove", "all", 1);
	}

	uiPupMenuEnd(C, pup);

	return OPERATOR_FINISHED;
}
static int rule_del_exec(bContext *C, wmOperator *UNUSED(op))
{
	Main *bmain = CTX_data_main(C);
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
	ParticleSettings *part = ptr.data;
	BoidRule *rule;
	BoidState *state;

	if (!part || part->phystype != PART_PHYS_BOIDS)
		return OPERATOR_CANCELLED;

	state = boid_get_current_state(part->boids);

	for (rule=state->rules.first; rule; rule=rule->next) {
		if (rule->flag & BOIDRULE_CURRENT) {
			BLI_remlink(&state->rules, rule);
			MEM_freeN(rule);
			break;
		}
	}
	rule = state->rules.first;

	if (rule)
		rule->flag |= BOIDRULE_CURRENT;

	DAG_relations_tag_update(bmain);
	DAG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);

	return OPERATOR_FINISHED;
}
示例#11
0
static int rule_move_down_exec(bContext *C, wmOperator *UNUSED(op))
{
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
	ParticleSystem *psys= ptr.data;
	Object *ob = ptr.id.data;
	BoidRule *rule;
	BoidState *state;

	if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
		return OPERATOR_CANCELLED;
	
	state = boid_get_current_state(psys->part->boids);
	for(rule = state->rules.first; rule; rule=rule->next) {
		if(rule->flag & BOIDRULE_CURRENT && rule->next) {
			BLI_remlink(&state->rules, rule);
			BLI_insertlink(&state->rules, rule->next, rule);

			DAG_id_tag_update(&psys->part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
			WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
			break;
		}
	}
	
	return OPERATOR_FINISHED;
}
示例#12
0
static int object_hook_recenter_exec(bContext *C, wmOperator *op)
{
	PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
	int num= RNA_enum_get(op->ptr, "modifier");
	Object *ob=NULL;
	HookModifierData *hmd=NULL;
	Scene *scene = CTX_data_scene(C);
	float bmat[3][3], imat[3][3];
	
	if (ptr.data) {		/* if modifier context is available, use that */
		ob = ptr.id.data;
		hmd= ptr.data;
	} 
	else {			/* use the provided property */
		ob = CTX_data_edit_object(C);
		hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
	}
	if (!ob || !hmd) {
		BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
		return OPERATOR_CANCELLED;
	}
	
	/* recenter functionality */
	copy_m3_m4(bmat, ob->obmat);
	invert_m3_m3(imat, bmat);
	
	sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
	mul_m3_v3(imat, hmd->cent);
	
	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
	
	return OPERATOR_FINISHED;
}
示例#13
0
static int object_hook_select_exec(bContext *C, wmOperator *op)
{
	PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
	int num= RNA_enum_get(op->ptr, "modifier");
	Object *ob=NULL;
	HookModifierData *hmd=NULL;
	
	if (ptr.data) {		/* if modifier context is available, use that */
		ob = ptr.id.data;
		hmd= ptr.data;
	} 
	else {			/* use the provided property */
		ob = CTX_data_edit_object(C);
		hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
	}
	if (!ob || !hmd) {
		BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
		return OPERATOR_CANCELLED;
	}
	
	/* select functionality */
	object_hook_select(ob, hmd);
	
	WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
	
	return OPERATOR_FINISHED;
}
示例#14
0
static int edit_controller_poll(bContext *C)
{
    PointerRNA ptr = CTX_data_pointer_get_type(C, "controller", &RNA_Controller);

    if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
    return 1;
}
示例#15
0
static int edit_actuator_poll(bContext *C)
{
    PointerRNA ptr = CTX_data_pointer_get_type(C, "actuator", &RNA_Actuator);

    if (ptr.data && ((ID *)ptr.id.data)->lib) return 0;
    return 1;
}
/************************ add/del boid rule operators *********************/
static int rule_add_exec(bContext *C, wmOperator *op)
{
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
	ParticleSettings *part = ptr.data;
	int type= RNA_enum_get(op->ptr, "type");

	BoidRule *rule;
	BoidState *state;

	if (!part || part->phystype != PART_PHYS_BOIDS)
		return OPERATOR_CANCELLED;

	state = boid_get_current_state(part->boids);

	for (rule=state->rules.first; rule; rule=rule->next)
		rule->flag &= ~BOIDRULE_CURRENT;

	rule = boid_new_rule(type);
	rule->flag |= BOIDRULE_CURRENT;

	BLI_addtail(&state->rules, rule);

	DAG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
	
	return OPERATOR_FINISHED;
}
示例#17
0
static int edit_actuator_poll(bContext *C)
{
	PointerRNA ptr = CTX_data_pointer_get_type(C, "actuator", &RNA_Actuator);

	if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0;
	return 1;
}
static int state_del_exec(bContext *C, wmOperator *UNUSED(op))
{
	Main *bmain = CTX_data_main(C);
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
	ParticleSettings *part = ptr.data;
	BoidState *state;

	if (!part || part->phystype != PART_PHYS_BOIDS)
		return OPERATOR_CANCELLED;

	for (state=part->boids->states.first; state; state=state->next) {
		if (state->flag & BOIDSTATE_CURRENT) {
			BLI_remlink(&part->boids->states, state);
			MEM_freeN(state);
			break;
		}
	}

	/* there must be at least one state */
	if (!part->boids->states.first) {
		state = boid_new_state(part->boids);
		BLI_addtail(&part->boids->states, state);
	}
	else
		state = part->boids->states.first;

	state->flag |= BOIDSTATE_CURRENT;

	DAG_relations_tag_update(bmain);
	DAG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
	
	return OPERATOR_FINISHED;
}
示例#19
0
/************************ add/del boid state operators *********************/
static int state_add_exec(bContext *C, wmOperator *UNUSED(op))
{
	PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
	ParticleSystem *psys= ptr.data;
	Object *ob= ptr.id.data;
	ParticleSettings *part;
	BoidState *state;

	if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
		return OPERATOR_CANCELLED;

	part = psys->part;

	for(state=part->boids->states.first; state; state=state->next)
		state->flag &= ~BOIDSTATE_CURRENT;

	state = boid_new_state(part->boids);
	state->flag |= BOIDSTATE_CURRENT;

	BLI_addtail(&part->boids->states, state);

	WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
	
	return OPERATOR_FINISHED;
}
示例#20
0
static int ptcache_add_new_exec(bContext *C, wmOperator *UNUSED(op))
{
	Scene *scene = CTX_data_scene(C);
	PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
	Object *ob= ptr.id.data;
	PointCache *cache= ptr.data;
	PTCacheID *pid;
	ListBase pidlist;

	BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
	
	for(pid=pidlist.first; pid; pid=pid->next) {
		if(pid->cache == cache) {
			*(pid->cache_ptr) = BKE_ptcache_add(pid->ptcaches);
			break;
		}
	}

	BLI_freelistN(&pidlist);

	WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
	WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);

	return OPERATOR_FINISHED;
}
示例#21
0
static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *op)
{
	Scene *scene= CTX_data_scene(C);
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
	Base *base;
	int retval= OPERATOR_CANCELLED;

	for(base=scene->base.first; base; base= base->next) {
		if(base->object->type==ob->type) {
			if(base->object!=ob && base->object->data==ob->data) {
				BLI_freelistN(&base->object->defbase);
				BLI_duplicatelist(&base->object->defbase, &ob->defbase);
				base->object->actdef= ob->actdef;

				DAG_id_flush_update(&base->object->id, OB_RECALC_DATA);
				WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
				WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);

				retval = OPERATOR_FINISHED;
			}
		}
	}

	return retval;
}
示例#22
0
static int shape_key_mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;

	if(!object_shape_key_mirror(C, ob))
		return OPERATOR_CANCELLED;

	return OPERATOR_FINISHED;
}
示例#23
0
/* ChildOf Constraint - set inverse callback */
static int childof_set_inverse_exec (bContext *C, wmOperator *op)
{
	PointerRNA ptr= CTX_data_pointer_get_type(C, "constraint", &RNA_ChildOfConstraint);
	Scene *scene= CTX_data_scene(C);
	Object *ob= ptr.id.data;
	bConstraint *con= ptr.data;
	bChildOfConstraint *data= (bChildOfConstraint *)con->data;
	bPoseChannel *pchan= NULL;

	/* try to find a pose channel */
	// TODO: get from context instead?
	if (ob && ob->pose)
		pchan= get_active_posechannel(ob);
	
	/* calculate/set inverse matrix */
	if (pchan) {
		float pmat[4][4], cinf;
		float imat[4][4], tmat[4][4];
		
		/* make copy of pchan's original pose-mat (for use later) */
		Mat4CpyMat4(pmat, pchan->pose_mat);
		
		/* disable constraint for pose to be solved without it */
		cinf= con->enforce;
		con->enforce= 0.0f;
		
		/* solve pose without constraint */
		where_is_pose(scene, ob);
		
		/* determine effect of constraint by removing the newly calculated 
		 * pchan->pose_mat from the original pchan->pose_mat, thus determining 
		 * the effect of the constraint
		 */
		Mat4Invert(imat, pchan->pose_mat);
		Mat4MulMat4(tmat, imat, pmat);
		Mat4Invert(data->invmat, tmat);
		
		/* recalculate pose with new inv-mat */
		con->enforce= cinf;
		where_is_pose(scene, ob);
	}
	else if (ob) {
		Object workob;
		/* use what_does_parent to find inverse - just like for normal parenting.
		 * NOTE: what_does_parent uses a static workob defined in object.c 
		 */
		what_does_parent(scene, ob, &workob);
		Mat4Invert(data->invmat, workob.obmat);
	}
	else
		Mat4One(data->invmat);
		
	WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
		
	return OPERATOR_FINISHED;
}
示例#24
0
static int vertex_group_poll_edit(bContext *C)
{
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
	ID *data= (ob)? ob->data: NULL;

	if(!(ob && !ob->id.lib && data && !data->lib))
		return 0;

	return vgroup_object_in_edit_mode(ob);
}
示例#25
0
static int limitdistance_reset_exec (bContext *C, wmOperator *op)
{
	PointerRNA ptr= CTX_data_pointer_get_type(C, "constraint", &RNA_LimitDistanceConstraint);
	
	/* just set distance to 0.0, which will cause a reset on next recalc */
	RNA_float_set(&ptr, "distance", 0.0f);
	
	WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, NULL);
	return OPERATOR_FINISHED;
}
示例#26
0
static int vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
	Mesh *me= ob->data;

	if(!ED_mesh_color_remove(C, ob, me))
		return OPERATOR_CANCELLED;

	return OPERATOR_FINISHED;
}
示例#27
0
static int shape_key_add_exec(bContext *C, wmOperator *op)
{
	Scene *scene= CTX_data_scene(C);
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
	int from_mix = RNA_boolean_get(op->ptr, "from_mix");

	ED_object_shape_key_add(C, scene, ob, from_mix);

	return OPERATOR_FINISHED;
}
示例#28
0
static int uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
{
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
	Mesh *me= ob->data;

	if(!ED_mesh_uv_texture_add(C, me, NULL, TRUE))
		return OPERATOR_CANCELLED;

	return OPERATOR_FINISHED;
}
示例#29
0
static int stretchto_reset_exec (bContext *C, wmOperator *op)
{
	PointerRNA ptr= CTX_data_pointer_get_type(C, "constraint", &RNA_StretchToConstraint);
	
	/* just set original length to 0.0, which will cause a reset on next recalc */
	RNA_float_set(&ptr, "original_length", 0.0f);
	
	WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, NULL);
	return OPERATOR_FINISHED;
}
示例#30
0
static int vertex_group_copy_exec(bContext *C, wmOperator *op)
{
	Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;

	vgroup_duplicate(ob);
	DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);

	return OPERATOR_FINISHED;
}