bool BL_ActionActuator::Update(double curtime, bool frame)
{
	bool bNegativeEvent = false;
	bool bPositiveEvent = false;
	bool bUseContinue = false;
	KX_GameObject *obj = (KX_GameObject*)GetParent();
	short playtype = BL_Action::ACT_MODE_PLAY;
	float start = m_startframe;
	float end = m_endframe;

	// If we don't have an action, we can't do anything
	if (!m_action)
		return false;

	// Convert our playtype to one that BL_Action likes
	switch(m_playtype)
	{
		case ACT_ACTION_LOOP_END:
		case ACT_ACTION_LOOP_STOP:
			playtype = BL_Action::ACT_MODE_LOOP;
			break;

		case ACT_ACTION_PINGPONG:
			// We handle ping pong ourselves to increase compabitility
			// with files made prior to animation changes from GSoC 2011.
			playtype = BL_Action::ACT_MODE_PLAY;
		
			if (m_flag & ACT_FLAG_REVERSE)
			{
				start = m_endframe;
				end = m_startframe;
			}

			break;
		case ACT_ACTION_FROM_PROP:
			CValue* prop = GetParent()->GetProperty(m_propname);

			// If we don't have a property, we can't do anything, so just bail
			if (!prop) return false;

			playtype = BL_Action::ACT_MODE_PLAY;
			start = end = prop->GetNumber();

			break;
	}

	if (m_flag & ACT_FLAG_CONTINUE)
		bUseContinue = true;
	
	
	// Handle events
	if (frame)
	{
		bNegativeEvent = m_negevent;
		bPositiveEvent = m_posevent;
		RemoveAllEvents();
	}

	// "Active" actions need to keep updating their current frame
	if (bUseContinue && (m_flag & ACT_FLAG_ACTIVE))
		m_localtime = obj->GetActionFrame(m_layer);

	if (m_flag & ACT_FLAG_ATTEMPT_PLAY)
		SetLocalTime(curtime);
	else
		ResetStartTime(curtime);

	// Handle a frame property if it's defined
	if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0)
	{
		CValue* oldprop = obj->GetProperty(m_framepropname);
		CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer));
		if (oldprop)
			oldprop->SetValue(newval);
		else
			obj->SetProperty(m_framepropname, newval);

		newval->Release();
	}

	// Handle a finished animation
	if ((m_flag & ACT_FLAG_PLAY_END) && (m_flag & ACT_FLAG_ACTIVE) && obj->IsActionDone(m_layer))
	{
		m_flag &= ~ACT_FLAG_ACTIVE;
		m_flag &= ~ACT_FLAG_ATTEMPT_PLAY;

		if (m_playtype == ACT_ACTION_PINGPONG)
			m_flag ^= ACT_FLAG_REVERSE;
		return false;
	}
	
	// If a different action is playing, we've been overruled and are no longer active
	if (obj->GetCurrentAction(m_layer) != m_action && !obj->IsActionDone(m_layer))
		m_flag &= ~ACT_FLAG_ACTIVE;

	if (bPositiveEvent || (m_flag & ACT_FLAG_ATTEMPT_PLAY && !(m_flag & ACT_FLAG_ACTIVE)))
	{
		if (bPositiveEvent && m_playtype == ACT_ACTION_PLAY)
		{
			if (obj->IsActionDone(m_layer))
				m_localtime = start;
			ResetStartTime(curtime);
		}

		if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags))
		{
			m_flag |= ACT_FLAG_ACTIVE;
			if (bUseContinue)
				obj->SetActionFrame(m_layer, m_localtime);

			if (m_playtype == ACT_ACTION_PLAY || m_playtype == ACT_ACTION_PINGPONG)
				m_flag |= ACT_FLAG_PLAY_END;
			else
				m_flag &= ~ACT_FLAG_PLAY_END;
		}
		m_flag |= ACT_FLAG_ATTEMPT_PLAY;
	}
	else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent)
	{	
		m_flag &= ~ACT_FLAG_ATTEMPT_PLAY;
		m_localtime = obj->GetActionFrame(m_layer);
		bAction *curr_action = obj->GetCurrentAction(m_layer);
		if (curr_action && curr_action != m_action)
		{
			// Someone changed the action on us, so we wont mess with it
			// Hopefully there wont be too many problems with two actuators using
			// the same action...
			m_flag &= ~ACT_FLAG_ACTIVE;
			return false;
		}

		switch(m_playtype)
		{
			case ACT_ACTION_LOOP_STOP:
				obj->StopAction(m_layer); // Stop the action after getting the frame

				// We're done
				m_flag &= ~ACT_FLAG_ACTIVE;
				return false;
			case ACT_ACTION_LOOP_END:
				// Convert into a play and let it finish
				obj->SetPlayMode(m_layer, BL_Action::ACT_MODE_PLAY);

				m_flag |= ACT_FLAG_PLAY_END;
				break;
	
			case ACT_ACTION_FLIPPER:
				// Convert into a play action and play back to the beginning
				end = start;
				start = obj->GetActionFrame(m_layer);
				obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags);

				m_flag |= ACT_FLAG_PLAY_END;
				break;
		}
	}

	return m_flag & ACT_FLAG_ACTIVE;
}
示例#2
0
void BL_Action::Update(float curtime)
{
	// Don't bother if we're done with the animation
	if (m_done)
		return;

	curtime -= KX_KetsjiEngine::GetSuspendedDelta();

	// Grab the start time here so we don't end up with a negative m_localtime when
	// suspending and resuming scenes.
	if (m_starttime < 0)
		m_starttime = curtime;

	if (m_calc_localtime)
		SetLocalTime(curtime);
	else
	{
		ResetStartTime(curtime);
		m_calc_localtime = true;
	}

	// Handle wrap around
	if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe)) {
		switch (m_playmode) {
			case ACT_MODE_PLAY:
				// Clamp
				m_localtime = m_endframe;
				m_done = true;
				break;
			case ACT_MODE_LOOP:
				// Put the time back to the beginning
				m_localtime = m_startframe;
				m_starttime = curtime;
				break;
			case ACT_MODE_PING_PONG:
				// Swap the start and end frames
				float temp = m_startframe;
				m_startframe = m_endframe;
				m_endframe = temp;

				m_starttime = curtime;

				break;
		}
	}

	if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
	{
		BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
		obj->GetPose(&m_pose);

		// Extract the pose from the action
		{
			Object *arm = obj->GetArmatureObject();
			bPose *temp = arm->pose;

			arm->pose = m_pose;
			animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);

			arm->pose = temp;
		}

		// Handle blending between armature actions
		if (m_blendin && m_blendframe<m_blendin)
		{
			IncrementBlending(curtime);

			// Calculate weight
			float weight = 1.f - (m_blendframe/m_blendin);

			// Blend the poses
			game_blend_poses(m_pose, m_blendinpose, weight);
		}


		// Handle layer blending
		if (m_layer_weight >= 0)
		{
			obj->GetMRDPose(&m_blendpose);
			game_blend_poses(m_pose, m_blendpose, m_layer_weight);
		}

		obj->SetPose(m_pose);

		obj->SetActiveAction(NULL, 0, curtime);
	}
	else
	{
		BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
		BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());

		// Handle shape actions if we have any
		if (shape_deformer && shape_deformer->GetKey())
		{
			Key *key = shape_deformer->GetKey();


			animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);

			// Handle blending between shape actions
			if (m_blendin && m_blendframe < m_blendin)
			{
				IncrementBlending(curtime);

				float weight = 1.f - (m_blendframe/m_blendin);

				// We go through and clear out the keyblocks so there isn't any interference
				// from other shape actions
				KeyBlock *kb;
				for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
					kb->curval = 0.f;

				// Now blend the shape
				BlendShape(key, weight, m_blendinshape);
			}

			// Handle layer blending
			if (m_layer_weight >= 0)
			{
				obj->GetShape(m_blendshape);
				BlendShape(key, m_layer_weight, m_blendshape);
			}

			obj->SetActiveAction(NULL, 0, curtime);
		}

		m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
	}
}
示例#3
0
void BL_Action::Update(float curtime, bool applyToObject)
{
	/* Don't bother if we're done with the animation and if the animation was already applied to the object.
	 * of if the animation made a double update for the same time and that it was applied to the object.
	 */
	if ((m_done && m_appliedToObject) || (m_prevUpdate == curtime && m_appliedToObject)) {
		return;
	}
	m_prevUpdate = curtime;

	curtime -= (float)KX_KetsjiEngine::GetSuspendedDelta();

	if (m_calc_localtime)
		SetLocalTime(curtime);
	else
	{
		ResetStartTime(curtime);
		m_calc_localtime = true;
	}

	// Handle wrap around
	if (m_localframe < std::min(m_startframe, m_endframe) || m_localframe > std::max(m_startframe, m_endframe)) {
		switch (m_playmode) {
			case ACT_MODE_PLAY:
				// Clamp
				m_localframe = m_endframe;
				m_done = true;
				break;
			case ACT_MODE_LOOP:
				// Put the time back to the beginning
				m_localframe = m_startframe;
				m_starttime = curtime;
				break;
			case ACT_MODE_PING_PONG:
				// Swap the start and end frames
				float temp = m_startframe;
				m_startframe = m_endframe;
				m_endframe = temp;

				m_starttime = curtime;

				break;
		}
	}

	m_appliedToObject = applyToObject;
	// In case of culled armatures (doesn't requesting to transform the object) we only manages time.
	if (!applyToObject) {
		return;
	}

	if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
	{
		BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;

		if (m_layer_weight >= 0)
			obj->GetPose(&m_blendpose);

		// Extract the pose from the action
		obj->SetPoseByAction(m_tmpaction, m_localframe);

		// Handle blending between armature actions
		if (m_blendin && m_blendframe<m_blendin)
		{
			IncrementBlending(curtime);

			// Calculate weight
			float weight = 1.f - (m_blendframe/m_blendin);

			// Blend the poses
			obj->BlendInPose(m_blendinpose, weight, ACT_BLEND_BLEND);
		}


		// Handle layer blending
		if (m_layer_weight >= 0)
			obj->BlendInPose(m_blendpose, m_layer_weight, m_blendmode);

		obj->UpdateTimestep(curtime);
	}
	else
	{
		BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
		BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());

		// Handle shape actions if we have any
		if (shape_deformer && shape_deformer->GetKey())
		{
			Key *key = shape_deformer->GetKey();

			PointerRNA ptrrna;
			RNA_id_pointer_create(&key->id, &ptrrna);

			animsys_evaluate_action(&ptrrna, m_tmpaction, NULL, m_localframe);

			// Handle blending between shape actions
			if (m_blendin && m_blendframe < m_blendin)
			{
				IncrementBlending(curtime);

				float weight = 1.f - (m_blendframe/m_blendin);

				// We go through and clear out the keyblocks so there isn't any interference
				// from other shape actions
				KeyBlock *kb;
				for (kb=(KeyBlock *)key->block.first; kb; kb=(KeyBlock *)kb->next)
					kb->curval = 0.f;

				// Now blend the shape
				BlendShape(key, weight, m_blendinshape);
			}

			// Handle layer blending
			if (m_layer_weight >= 0)
			{
				obj->GetShape(m_blendshape);
				BlendShape(key, m_layer_weight, m_blendshape);
			}

			obj->SetActiveAction(0, curtime);
		}
	}
}