Example #1
0
// does copy_fcurve...
void BKE_action_make_local(bAction *act)
{
	tMakeLocalActionContext mlac = {act, NULL, false, false};
	Main *bmain = G.main;
	
	if (act->id.lib == NULL)
		return;
	
	/* XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default */
	if ((act->id.flag & LIB_FAKEUSER) && (act->id.us <= 1)) {
		id_clear_lib_data(bmain, &act->id);
		return;
	}
	
	BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac);
	
	if (mlac.is_local && mlac.is_lib == false) {
		id_clear_lib_data(bmain, &act->id);
	}
	else if (mlac.is_local && mlac.is_lib) {
		mlac.act_new = BKE_action_copy(act);
		mlac.act_new->id.us = 0;

		BKE_id_lib_local_paths(bmain, act->id.lib, &mlac.act_new->id);

		BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac);
	}
}
Example #2
0
static int act_new_exec(bContext *C, wmOperator *UNUSED(op))
{
	PointerRNA ptr, idptr;
	PropertyRNA *prop;

	/* hook into UI */
	uiIDContextProperty(C, &ptr, &prop);
	
	if (prop) {
		bAction *action = NULL, *oldact = NULL;
		PointerRNA oldptr;
		
		/* create action - the way to do this depends on whether we've got an
		 * existing one there already, in which case we make a copy of it
		 * (which is useful for "versioning" actions within the same file)
		 */
		oldptr = RNA_property_pointer_get(&ptr, prop);
		oldact = (bAction *)oldptr.id.data;
		
		if (oldact && GS(oldact->id.name) == ID_AC) {
			/* make a copy of the existing action */
			action = BKE_action_copy(oldact);
		}
		else {
			Main *bmain = CTX_data_main(C);

			/* just make a new (empty) action */
			action = add_empty_action(bmain, "Action");
		}
		
		/* when creating new ID blocks, use is already 1 (fake user), 
		 * but RNA pointer use also increases user, so this compensates it 
		 */
		action->id.us--;
		
		RNA_id_pointer_create(&action->id, &idptr);
		RNA_property_pointer_set(&ptr, prop, idptr);
		RNA_property_update(C, &ptr, prop);
	}
	
	/* set notifier that keyframes have changed */
	WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
	
	return OPERATOR_FINISHED;
}
Example #3
0
/* Create new action */
static bAction *action_create_new(bContext *C, bAction *oldact)
{
	ScrArea *sa = CTX_wm_area(C);
	bAction *action;
	
	/* create action - the way to do this depends on whether we've got an
	 * existing one there already, in which case we make a copy of it
	 * (which is useful for "versioning" actions within the same file)
	 */
	if (oldact && GS(oldact->id.name) == ID_AC) {
		/* make a copy of the existing action */
		action = BKE_action_copy(CTX_data_main(C), oldact);
	}
	else {
		/* just make a new (empty) action */
		action = add_empty_action(CTX_data_main(C), "Action");
	}
	
	/* when creating new ID blocks, there is already 1 user (as for all new datablocks), 
	 * but the RNA pointer code will assign all the proper users instead, so we compensate
	 * for that here
	 */
	BLI_assert(action->id.us == 1);
	id_us_min(&action->id);
	
	/* set ID-Root type */
	if (sa->spacetype == SPACE_ACTION) {
		SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
		
		if (saction->mode == SACTCONT_SHAPEKEY)
			action->idroot = ID_KE;
		else
			action->idroot = ID_OB;
	}
	
	return action;
}
Example #4
0
/* returns 1 if its OK */
static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
{
	bNodeLink *link, *linkn, *tlink;
	bNode *node, *nextnode;
	bNodeTree *ngroup, *wgroup;
	ListBase anim_basepaths = {NULL, NULL};
	
	ngroup = (bNodeTree *)gnode->id;
	
	/* clear new pointers, set in copytree */
	for (node = ntree->nodes.first; node; node = node->next)
		node->new_node = NULL;
	
	/* wgroup is a temporary copy of the NodeTree we're merging in
	 * - all of wgroup's nodes are transferred across to their new home
	 * - ngroup (i.e. the source NodeTree) is left unscathed
	 * - temp copy. don't change ID usercount
	 */
	wgroup = ntreeCopyTree_ex(ngroup, FALSE);
	
	/* Add the nodes into the ntree */
	for (node = wgroup->nodes.first; node; node = nextnode) {
		nextnode = node->next;
		
		/* Remove interface nodes.
		 * This also removes remaining links to and from interface nodes.
		 */
		if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
			nodeFreeNode(wgroup, node);
			continue;
		}
		
		/* keep track of this node's RNA "base" path (the part of the path identifying the node) 
		 * if the old nodetree has animation data which potentially covers this node
		 */
		if (wgroup->adt) {
			PointerRNA ptr;
			char *path;
			
			RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr);
			path = RNA_path_from_ID_to_struct(&ptr);
			
			if (path)
				BLI_addtail(&anim_basepaths, BLI_genericNodeN(path));
		}
		
		/* migrate node */
		BLI_remlink(&wgroup->nodes, node);
		BLI_addtail(&ntree->nodes, node);
		
		/* ensure unique node name in the node tree */
		nodeUniqueName(ntree, node);
		
		if (!node->parent) {
			node->locx += gnode->locx;
			node->locy += gnode->locy;
		}
		
		node->flag |= NODE_SELECT;
	}
	
	/* Add internal links to the ntree */
	for (link = wgroup->links.first; link; link = linkn) {
		linkn = link->next;
		BLI_remlink(&wgroup->links, link);
		BLI_addtail(&ntree->links, link);
	}
	
	/* and copy across the animation,
	 * note that the animation data's action can be NULL here */
	if (wgroup->adt) {
		LinkData *ld, *ldn = NULL;
		bAction *waction;
		
		/* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */
		waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action);
		
		/* now perform the moving */
		BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths);
		
		/* paths + their wrappers need to be freed */
		for (ld = anim_basepaths.first; ld; ld = ldn) {
			ldn = ld->next;
			
			MEM_freeN(ld->data);
			BLI_freelinkN(&anim_basepaths, ld);
		}
		
		/* free temp action too */
		if (waction) {
			BKE_libblock_free(&G.main->action, waction);
		}
	}
	
	/* free the group tree (takes care of user count) */
	BKE_libblock_free(&G.main->nodetree, wgroup);
	
	/* restore external links to and from the gnode */
	/* note: the nodes have been copied to intermediate wgroup first (so need to use new_node),
	 *       then transferred to ntree (new_node pointers remain valid).
	 */
	
	/* input links */
	for (link = ngroup->links.first; link; link = link->next) {
		if (link->fromnode->type == NODE_GROUP_INPUT) {
			const char *identifier = link->fromsock->identifier;
			int num_external_links = 0;
			
			/* find external links to this input */
			for (tlink = ntree->links.first; tlink; tlink = tlink->next) {
				if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
					nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode->new_node, link->tosock->new_sock);
					++num_external_links;
				}
			}
			
			/* if group output is not externally linked,
			 * convert the constant input value to ensure somewhat consistent behavior */
			if (num_external_links == 0) {
				/* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier);
				BLI_assert(sock);*/
				
				/* XXX TODO nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, ntree, sock, gnode);*/
			}
		}
	}
	
	/* output links */
	for (link = ntree->links.first; link; link = link->next) {
		if (link->fromnode == gnode) {
			const char *identifier = link->fromsock->identifier;
			int num_internal_links = 0;
			
			/* find internal links to this output */
			for (tlink = ngroup->links.first; tlink; tlink = tlink->next) {
				/* only use active output node */
				if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) {
					if (STREQ(tlink->tosock->identifier, identifier)) {
						nodeAddLink(ntree, tlink->fromnode->new_node, tlink->fromsock->new_sock, link->tonode, link->tosock);
						++num_internal_links;
					}
				}
			}
			
			/* if group output is not internally linked,
			 * convert the constant output value to ensure somewhat consistent behavior */
			if (num_internal_links == 0) {
				/* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier);
				BLI_assert(sock);*/
				
				/* XXX TODO nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */
			}
		}
	}
	
	/* delete the group instance */
	nodeFreeNode(ntree, gnode);
	
	ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
	
	return 1;
}
Example #5
0
int id_copy(ID *id, ID **newid, int test)
{
    if (!test) *newid = NULL;

    /* conventions:
     * - make shallow copy, only this ID block
     * - id.us of the new ID is set to 1 */
    switch (GS(id->name)) {
    case ID_SCE:
        return 0; /* can't be copied from here */
    case ID_LI:
        return 0; /* can't be copied from here */
    case ID_OB:
        if (!test) *newid = (ID *)BKE_object_copy((Object *)id);
        return 1;
    case ID_ME:
        if (!test) *newid = (ID *)BKE_mesh_copy((Mesh *)id);
        return 1;
    case ID_CU:
        if (!test) *newid = (ID *)BKE_curve_copy((Curve *)id);
        return 1;
    case ID_MB:
        if (!test) *newid = (ID *)BKE_mball_copy((MetaBall *)id);
        return 1;
    case ID_MA:
        if (!test) *newid = (ID *)BKE_material_copy((Material *)id);
        return 1;
    case ID_TE:
        if (!test) *newid = (ID *)BKE_texture_copy((Tex *)id);
        return 1;
    case ID_IM:
        if (!test) *newid = (ID *)BKE_image_copy((Image *)id);
        return 1;
    case ID_LT:
        if (!test) *newid = (ID *)BKE_lattice_copy((Lattice *)id);
        return 1;
    case ID_LA:
        if (!test) *newid = (ID *)BKE_lamp_copy((Lamp *)id);
        return 1;
    case ID_SPK:
        if (!test) *newid = (ID *)BKE_speaker_copy((Speaker *)id);
        return 1;
    case ID_CA:
        if (!test) *newid = (ID *)BKE_camera_copy((Camera *)id);
        return 1;
    case ID_IP:
        return 0; /* deprecated */
    case ID_KE:
        if (!test) *newid = (ID *)BKE_key_copy((Key *)id);
        return 1;
    case ID_WO:
        if (!test) *newid = (ID *)BKE_world_copy((World *)id);
        return 1;
    case ID_SCR:
        return 0; /* can't be copied from here */
    case ID_VF:
        return 0; /* not implemented */
    case ID_TXT:
        if (!test) *newid = (ID *)BKE_text_copy((Text *)id);
        return 1;
    case ID_SCRIPT:
        return 0; /* deprecated */
    case ID_SO:
        return 0; /* not implemented */
    case ID_GR:
        if (!test) *newid = (ID *)BKE_group_copy((Group *)id);
        return 1;
    case ID_AR:
        if (!test) *newid = (ID *)BKE_armature_copy((bArmature *)id);
        return 1;
    case ID_AC:
        if (!test) *newid = (ID *)BKE_action_copy((bAction *)id);
        return 1;
    case ID_NT:
        if (!test) *newid = (ID *)ntreeCopyTree((bNodeTree *)id);
        return 1;
    case ID_BR:
        if (!test) *newid = (ID *)BKE_brush_copy((Brush *)id);
        return 1;
    case ID_PA:
        if (!test) *newid = (ID *)BKE_particlesettings_copy((ParticleSettings *)id);
        return 1;
    case ID_WM:
        return 0; /* can't be copied from here */
    case ID_GD:
        return 0; /* not implemented */
    }

    return 0;
}
Example #6
0
bool BL_Action::Play(const std::string& name,
					float start,
					float end,
					short priority,
					float blendin,
					short play_mode,
					float layer_weight,
					short ipo_flags,
					float playback_speed,
					short blend_mode)
{

	// Only start playing a new action if we're done, or if
	// the new action has a higher priority
	if (!IsDone() && priority > m_priority)
		return false;
	m_priority = priority;
	bAction* prev_action = m_action;

	KX_Scene* kxscene = m_obj->GetScene();

	// First try to load the action
	m_action = (bAction*)kxscene->GetLogicManager()->GetActionByName(name);
	if (!m_action)
	{
		CM_Error("failed to load action: " << name);
		m_done = true;
		return false;
	}

	// If we have the same settings, don't play again
	// This is to resolve potential issues with pulses on sensors such as the ones
	// reported in bug #29412. The fix is here so it works for both logic bricks and Python.
	// However, this may eventually lead to issues where a user wants to override an already
	// playing action with the same action and settings. If this becomes an issue,
	// then this fix may have to be re-evaluated.
	if (!IsDone() && m_action == prev_action && m_startframe == start && m_endframe == end
			&& m_priority == priority && m_speed == playback_speed)
		return false;

	// Keep a copy of the action for threading purposes
	if (m_tmpaction) {
		BKE_libblock_free(G.main, m_tmpaction);
		m_tmpaction = NULL;
	}
	m_tmpaction = BKE_action_copy(G.main, m_action);

	// First get rid of any old controllers
	ClearControllerList();

	// Create an SG_Controller
	SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, kxscene->GetSceneConverter());
	m_sg_contr_list.push_back(sg_contr);
	m_obj->GetSGNode()->AddSGController(sg_contr);
	sg_contr->SetObject(m_obj->GetSGNode());

	// World
	sg_contr = BL_CreateWorldIPO(m_action, kxscene->GetBlenderScene()->world, kxscene->GetSceneConverter());
	if (sg_contr) {
		m_sg_contr_list.push_back(sg_contr);
		m_obj->GetSGNode()->AddSGController(sg_contr);
		sg_contr->SetObject(m_obj->GetSGNode());
	}

	// Try obcolor
	sg_contr = BL_CreateObColorIPO(m_action, m_obj, kxscene->GetSceneConverter());
	if (sg_contr) {
		m_sg_contr_list.push_back(sg_contr);
		m_obj->GetSGNode()->AddSGController(sg_contr);
		sg_contr->SetObject(m_obj->GetSGNode());
	}

	// Now try materials
	for (int matidx = 1; matidx <= m_obj->GetBlenderObject()->totcol; ++matidx) {
		Material *mat = give_current_material(m_obj->GetBlenderObject(), matidx);
		if (!mat) {
			continue;
		}

		KX_BlenderSceneConverter *converter = kxscene->GetSceneConverter();
		RAS_IPolyMaterial *polymat = converter->FindCachedPolyMaterial(kxscene, mat);
		if (!polymat) {
			continue;
		}

		sg_contr = BL_CreateMaterialIpo(m_action, mat, polymat, m_obj, converter);
		if (sg_contr) {
			m_sg_contr_list.push_back(sg_contr);
			m_obj->GetSGNode()->AddSGController(sg_contr);
			sg_contr->SetObject(m_obj->GetSGNode());
		}
	}

	// Extra controllers
	if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT)
	{
		sg_contr = BL_CreateLampIPO(m_action, m_obj, kxscene->GetSceneConverter());
		m_sg_contr_list.push_back(sg_contr);
		m_obj->GetSGNode()->AddSGController(sg_contr);
		sg_contr->SetObject(m_obj->GetSGNode());
	}
	else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA)
	{
		sg_contr = BL_CreateCameraIPO(m_action, m_obj, kxscene->GetSceneConverter());
		m_sg_contr_list.push_back(sg_contr);
		m_obj->GetSGNode()->AddSGController(sg_contr);
		sg_contr->SetObject(m_obj->GetSGNode());
	}
	
	m_ipo_flags = ipo_flags;
	InitIPO();

	// Setup blendin shapes/poses
	if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
	{
		BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
		obj->GetPose(&m_blendinpose);
	}
	else
	{
		BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
		BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
		
		if (shape_deformer && shape_deformer->GetKey())
		{
			obj->GetShape(m_blendinshape);

			// Now that we have the previous blend shape saved, we can clear out the key to avoid any
			// further interference.
			KeyBlock *kb;
			for (kb=(KeyBlock *)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock *)kb->next)
				kb->curval = 0.f;
		}
	}

	// Now that we have an action, we have something we can play
	m_starttime = KX_GetActiveEngine()->GetFrameTime() - kxscene->getSuspendedDelta();
	m_startframe = m_localframe = start;
	m_endframe = end;
	m_blendin = blendin;
	m_playmode = play_mode;
	m_blendmode = blend_mode;
	m_blendframe = 0.f;
	m_blendstart = 0.f;
	m_speed = playback_speed;
	m_layer_weight = layer_weight;
	
	m_done = false;
	m_appliedToObject = false;

	m_prevUpdate = -1.0f;

	return true;
}