/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "motion/motion_automation_source.h"
		#include "motion/motion.h"
		#include "automation/automation_source_group.h"
		#include "automation/automation_player.h"

		using namespace GS::Automation;


//------------------------------------------------------------------------------
void				MotionSource::Evaluate(Player &target)
{
	if	(motion == NULL)
		return;

	ListForeachPtr(MotionChannel *, channel, motion->GetChannelList())
	{
		if	(channel->GetPointCount() == 0)
			continue;

		// Skip rotation channels if using quaternion.
		if	(motion->GetUseQuaternion())
			switch (channel->type)
			{
				case MotionChannel::XRot:
				case MotionChannel::YRot:
				case MotionChannel::ZRot:
					continue;

				default: break;
			}

		// Evaluate channel.
		float v;
		channel->Evaluate(time, &v, loop_mode, loop_start, loop_end);

		// Relative mode.
		switch (channel->type)
		{
			case MotionChannel::XPos:
			case MotionChannel::YPos:
			case MotionChannel::ZPos:
			{
				float _v = v, s;
				if	(relative && target.property_provider->GetProperty(channel->type, s))
					v = s + v - p_pos[channel->type - MotionChannel::XPos];
				p_pos[channel->type - MotionChannel::XPos] = _v;
			}
			break;

			case MotionChannel::XRot:
			case MotionChannel::YRot:
			case MotionChannel::ZRot:
			{
				float _v = v, s;
				if	(relative && target.property_provider->GetProperty(channel->type, s))
					v = s + v - p_euler[channel->type - MotionChannel::XRot];
				p_euler[channel->type - MotionChannel::XRot] = _v;
			}
			break;

			default: break;
		}

		target.BlendAutomatedProperty(channel->type, v, GetWeight());
	}
}
bool				MotionSource::EvaluateRotation(GS::Quaternion &q)
{
	if	(!motion->GetUseQuaternion())
		return false;

	Quaternion s = q;
	motion->GetQuaternion().Evaluate(time, q, loop_mode, loop_start, loop_end);

	Quaternion _q = q;
	if	(relative)
		q = (q * p_quat.Inverse()) * s;
	p_quat = _q;
	return true;
}
bool				MotionSource::IsDone() const
{
	if	(!motion)
		return true;

	switch (loop_mode)
	{
		case Curve::Repeat:
		case Curve::OffsetAndRepeat:
		case Curve::Oscillate:
			break;

		default:
			if	(time_scale > 0)
			{
				if	(time > loop_end)
					return true;
			}
			else
				if	(time < loop_start)
					return true;
			break;
	}
	return false;
}
MotionSource::MotionSource(Motion *_motion, SourceGroup *_group)
{
	type = TypeMotion;
	motion = _motion;

	loop_mode = Curve::Constant;

	if	(motion)
	{
		TimeRange range = motion->GetTimeRange();
		loop_start = range.start;
		loop_end = range.end;
	}
	else
	{
		loop_start = Time::Inf;
		loop_end = Time::Inf;
	}

	// Evaluate relative position/euler.
	relative = false;

	motion->EvaluatePosition(loop_start, p_pos, loop_mode);
	if	(motion->GetUseQuaternion())
			motion->GetQuaternion().Evaluate(loop_start, p_quat, loop_mode);
	else	motion->EvaluateRotation(loop_start, p_euler, loop_mode);

	group = _group;
	if	(group)
		group->source_list.Add(this, true, false);
}
//------------------------------------------------------------------------------
