Blame synfig-core/src/modules/lyr_std/timeloop.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file timeloop.cpp
Carlos Lopez a09598
**	\brief Implementation of the "Time Loop" layer
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007, 2008 Chris Moore
Carlos Lopez e83454
**	Copyright (c) 2011-2013 Carlos Lรณpez
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
**
Carlos Lopez a09598
** === N O T E S ===========================================================
Carlos Lopez a09598
**
Carlos Lopez a09598
** ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
bw 94d8a6
#include <synfig localization.h=""></synfig>
bw 94d8a6
#include <synfig general.h=""></synfig>
bw 94d8a6
Carlos Lopez a09598
#include "timeloop.h"
Carlos Lopez a09598
#include <synfig valuenode.h=""></synfig>
Diego Barrios Romero 07d34c
#include <synfig valuenode_const.h="" valuenodes=""></synfig>
Diego Barrios Romero 07d34c
#include <synfig valuenode_subtract.h="" valuenodes=""></synfig>
Carlos Lopez a09598
#include <synfig time.h=""></synfig>
Carlos Lopez a09598
#include <synfig context.h=""></synfig>
Carlos Lopez a09598
#include <synfig paramdesc.h=""></synfig>
Carlos Lopez a09598
#include <synfig renddesc.h=""></synfig>
Carlos Lopez a09598
#include <synfig value.h=""></synfig>
Carlos Lopez e8b629
#include <synfig canvas.h=""></synfig>
Carlos Lopez a09598
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
using namespace std;
Carlos Lopez a09598
using namespace etl;
9f3c68
using namespace synfig;
144d3f
using namespace modules;
9f3c68
using namespace lyr_std;
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
SYNFIG_LAYER_INIT(Layer_TimeLoop);
Carlos Lopez a09598
SYNFIG_LAYER_SET_NAME(Layer_TimeLoop,"timeloop");
Carlos Lopez a09598
SYNFIG_LAYER_SET_LOCAL_NAME(Layer_TimeLoop,N_("Time Loop"));
caryoscelus 2dbbd0
SYNFIG_LAYER_SET_CATEGORY(Layer_TimeLoop,N_("Time"));
Carlos Lopez a09598
SYNFIG_LAYER_SET_VERSION(Layer_TimeLoop,"0.2");
Carlos Lopez a09598
SYNFIG_LAYER_SET_CVS_ID(Layer_TimeLoop,"$Id$");
Carlos Lopez a09598
Carlos Lopez a09598
/* === P R O C E D U R E S ================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
Layer_TimeLoop::Layer_TimeLoop()
Carlos Lopez a09598
{
Carlos Lopez a09598
	old_version=false;
Carlos Lopez 235206
	param_only_for_positive_duration=ValueBase(false);
Carlos Lopez 235206
	param_symmetrical=ValueBase(true);
Carlos Lopez 235206
	param_link_time=ValueBase(Time(0));
Carlos Lopez 235206
	param_local_time=ValueBase(Time(0));
Carlos Lopez 235206
	param_duration=ValueBase(Time(1));
Carlos Lopez 235206
Carlos Lopez 235206
	SET_INTERPOLATION_DEFAULTS();
Carlos Lopez 235206
	SET_STATIC_DEFAULTS();
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Layer_TimeLoop::~Layer_TimeLoop()
Carlos Lopez a09598
{
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
Layer_TimeLoop::set_param(const String & param, const ValueBase &value)
Carlos Lopez a09598
{
Carlos Lopez a09598
	if(old_version)
Carlos Lopez a09598
	{
Carlos Lopez 235206
		if(param=="start_time" && value.same_type_as(start_time))
Carlos Lopez 235206
		{
Carlos Lopez 235206
			value.put(&start_time);
Carlos Lopez 235206
			return true;
Carlos Lopez 235206
		}
Carlos Lopez 235206
		if(param=="end_time" && value.same_type_as(end_time))
Carlos Lopez 235206
		{
Carlos Lopez 235206
			value.put(&end_time);
Carlos Lopez 235206
			return true;
Carlos Lopez 235206
		}
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
	{
Carlos Lopez 235206
		IMPORT_VALUE(param_local_time);
Carlos Lopez 235206
		IMPORT_VALUE(param_link_time);
Carlos Lopez 235206
		IMPORT_VALUE(param_duration);
Carlos Lopez 235206
		IMPORT_VALUE(param_only_for_positive_duration);
Carlos Lopez 235206
		IMPORT_VALUE(param_symmetrical);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	return Layer::set_param(param,value);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
ValueBase
Carlos Lopez a09598
Layer_TimeLoop::get_param(const String & param)const
Carlos Lopez a09598
{
Carlos Lopez 235206
	EXPORT_VALUE(param_link_time);
Carlos Lopez 235206
	EXPORT_VALUE(param_local_time);
Carlos Lopez 235206
	EXPORT_VALUE(param_duration);
Carlos Lopez 235206
	EXPORT_VALUE(param_only_for_positive_duration);
Carlos Lopez 235206
	EXPORT_VALUE(param_symmetrical);
Carlos Lopez a09598
	EXPORT_NAME();
Carlos Lopez a09598
	EXPORT_VERSION();
Carlos Lopez a09598
Carlos Lopez a09598
	return Layer::get_param(param);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Layer::Vocab
Carlos Lopez a09598
Layer_TimeLoop::get_param_vocab()const
Carlos Lopez a09598
{
Carlos Lopez a09598
	Layer::Vocab ret(Layer::get_param_vocab());
Carlos Lopez a09598
Carlos Lopez a09598
	ret.push_back(ParamDesc("link_time")
Carlos Lopez a09598
		.set_local_name(_("Link Time"))
Carlos Lopez 42e8f2
		.set_description(_("Start time of the loop for the cycled context"))
9131f2
		.set_static(true)
Carlos Lopez a09598
	);
Carlos Lopez a09598
Carlos Lopez a09598
	ret.push_back(ParamDesc("local_time")
Carlos Lopez a09598
		.set_local_name(_("Local Time"))
Carlos Lopez 42e8f2
		.set_description(_("The time when the resulted loop starts"))
9131f2
		.set_static(true)
Carlos Lopez a09598
	);
Carlos Lopez a09598
Carlos Lopez a09598
	ret.push_back(ParamDesc("duration")
Carlos Lopez a09598
		.set_local_name(_("Duration"))
luz.paz 99f3ef
		.set_description(_("Length of the loop"))
9131f2
		.set_static(true)
Carlos Lopez a09598
	);
Carlos Lopez a09598
Carlos Lopez a09598
	ret.push_back(ParamDesc("only_for_positive_duration")
Carlos Lopez a09598
		.set_local_name(_("Only For Positive Duration"))
Carlos Lopez 42e8f2
		.set_description(_("When checked will loop only positive durations"))
9131f2
		.set_static(true)
Carlos Lopez a09598
	);
Carlos Lopez a09598
Carlos Lopez a09598
	ret.push_back(ParamDesc("symmetrical")
Carlos Lopez a09598
		.set_local_name(_("Symmetrical"))
Carlos Lopez 42e8f2
		.set_description(_("When checked, loops are mirrored centered at Local Time"))
9131f2
		.set_static(true)
Carlos Lopez a09598
	);
Carlos Lopez a09598
Carlos Lopez a09598
	return ret;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
Layer_TimeLoop::set_version(const String &ver)
Carlos Lopez a09598
{
Carlos Lopez a09598
	if (ver=="0.1")
Carlos Lopez a09598
		old_version = true;
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Layer_TimeLoop::reset_version()
Carlos Lopez a09598
{
Carlos Lopez 235206
	Time link_time, local_time, duration;
Carlos Lopez 235206
	bool only_for_positive_duration, symmetrical;
Carlos Lopez a09598
	// if we're not converting from an old version of the layer, there's nothing to do
Carlos Lopez a09598
	if (!old_version)
Carlos Lopez a09598
		return;
Carlos Lopez a09598
Carlos Lopez a09598
	old_version = false;
Carlos Lopez a09598
Carlos Lopez a09598
	// these are the conversions to go from 0.1 to 0.2:
Carlos Lopez a09598
	//
Carlos Lopez a09598
	//	 local_time = start_time
Carlos Lopez a09598
	//	 duration = end_time - start_time
Carlos Lopez a09598
	//	 if (time < start_time)
Carlos Lopez a09598
	//	   link_time = -duration : if we want to reproduce the old behaviour - do we?
Carlos Lopez a09598
	//	 else
Carlos Lopez a09598
	//		 link_time = 0
Carlos Lopez a09598
Carlos Lopez a09598
	// convert the static parameters
Carlos Lopez a09598
	local_time = start_time;
Carlos Lopez a09598
	duration = end_time - start_time;
Carlos Lopez a09598
	only_for_positive_duration = true;
Carlos Lopez a09598
	symmetrical = false;
Carlos Lopez a09598
Carlos Lopez 235206
	param_local_time.set(local_time);
Carlos Lopez 235206
	param_duration.set(duration);
Carlos Lopez 235206
	param_only_for_positive_duration.set(only_for_positive_duration);
Carlos Lopez 235206
	param_symmetrical.set(symmetrical);
Carlos Lopez 235206
	
Carlos Lopez a09598
	//! \todo layer version 0.1 acted differently before start_time was reached - possibly due to a bug
Carlos Lopez a09598
	link_time = 0;
Carlos Lopez 235206
	param_link_time.set(link_time);
Carlos Lopez a09598
Carlos Lopez a09598
	// convert the dynamic parameters
Carlos Lopez a09598
	const DynamicParamList &dpl = dynamic_param_list();
Carlos Lopez a09598
Carlos Lopez a09598
	// if neither start_time nor end_time are dynamic, there's nothing more to do
Carlos Lopez a09598
	if (dpl.count("start_time") == 0 && dpl.count("end_time") == 0)
Carlos Lopez a09598
		return;
Carlos Lopez a09598
Carlos Lopez a09598
	etl::rhandle<valuenode> start_time_value_node, end_time_value_node;</valuenode>
Carlos Lopez a09598
	LinkableValueNode* duration_value_node;
Carlos Lopez a09598
Carlos Lopez a09598
	if (dpl.count("start_time"))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		start_time_value_node = dpl.find("start_time")->second;
Carlos Lopez a09598
		disconnect_dynamic_param("start_time");
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
		start_time_value_node = ValueNode_Const::create(start_time);
Carlos Lopez a09598
Carlos Lopez a09598
	if (dpl.count("end_time"))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		end_time_value_node = dpl.find("end_time")->second;
Carlos Lopez a09598
		disconnect_dynamic_param("end_time");
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
		end_time_value_node = ValueNode_Const::create(end_time);
Carlos Lopez a09598
Carlos Lopez a09598
	duration_value_node = ValueNode_Subtract::create(Time(0));
Carlos Lopez a09598
	duration_value_node->set_link("lhs", end_time_value_node);
Carlos Lopez a09598
	duration_value_node->set_link("rhs", start_time_value_node);
Carlos Lopez a09598
Carlos Lopez a09598
	connect_dynamic_param("local_time", start_time_value_node);
Carlos Lopez a09598
	connect_dynamic_param("duration",   duration_value_node);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
dd97a8
Layer_TimeLoop::set_time_vfunc(IndependentContext context, Time t)const
Carlos Lopez a09598
{
Carlos Lopez 235206
	Time link_time=param_link_time.get(Time());
Carlos Lopez 235206
	Time local_time=param_local_time.get(Time());
Carlos Lopez 235206
	Time duration=param_duration.get(Time());
Carlos Lopez 235206
	bool only_for_positive_duration=param_only_for_positive_duration.get(bool());
Carlos Lopez 235206
	bool symmetrical=param_symmetrical.get(bool());
Carlos Lopez 235206
	
Carlos Lopez a09598
	Time time = t;
Carlos Lopez e8b629
	float document_fps=get_canvas()->rend_desc().get_frame_rate();
Carlos Lopez a09598
	if (!only_for_positive_duration || duration > 0)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if (duration == 0)
Carlos Lopez a09598
			t = link_time;
Carlos Lopez e8b629
		else {
Carlos Lopez e8b629
			float t_frames = round(t*document_fps);
Carlos Lopez e8b629
			float duration_frames = round(duration*document_fps);
Carlos Lopez e8b629
			if (duration > 0)
Carlos Lopez e8b629
			{
Carlos Lopez e8b629
				t -= local_time;
Carlos Lopez e8b629
				// Simple formula looks like this:
Carlos Lopez e8b629
				// t -= floor(t / duration) * duration;
Carlos Lopez e8b629
				// but we should make all calculations in frames to avoid round errors
Carlos Lopez e8b629
				t_frames -= floor(t_frames / duration_frames) * duration_frames;
Carlos Lopez e8b629
				// converting back to seconds:
Carlos Lopez e8b629
				t = t_frames / document_fps;
Carlos Lopez e8b629
				t = link_time + t;
Carlos Lopez e8b629
			}
Carlos Lopez e8b629
			else
Carlos Lopez e8b629
			{
Carlos Lopez e8b629
				t -= local_time;
Carlos Lopez e8b629
				// Simple formula looks like this:
Carlos Lopez e8b629
				// t -= floor(t / -duration) * -duration;
Carlos Lopez e8b629
				// but we should make all calculations in frames to avoid round errors
Carlos Lopez e8b629
				t_frames -= floor(t_frames / -duration_frames) * -duration_frames;
Carlos Lopez e8b629
				// converting back to seconds:
Carlos Lopez e8b629
				t = t_frames / document_fps;
Carlos Lopez e8b629
				t = link_time - t;
Carlos Lopez e8b629
			}
Carlos Lopez a09598
		}
Carlos Lopez a09598
		// for compatibility with v0.1 layers; before local_time is reached, take a step back
Carlos Lopez a09598
		if (!symmetrical && time < local_time)
Carlos Lopez a09598
			t -= duration;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	context.set_time(t);
Carlos Lopez a09598
}