1 /* === S Y N F I G ========================================================= */
2 /*!	\file timegather.cpp
3 **	\brief Time Gather File
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	Copyright (c) 2004 Adrian Bentley
9 **	Copyright (c) 2007 Chris Moore
10 **
11 **	This package is free software; you can redistribute it and/or
12 **	modify it under the terms of the GNU General Public License as
13 **	published by the Free Software Foundation; either version 2 of
14 **	the License, or (at your option) any later version.
15 **
16 **	This package is distributed in the hope that it will be useful,
17 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **	General Public License for more details.
20 **	\endlegal
21 */
22 /* ========================================================================= */
23 
24 /* === H E A D E R S ======================================================= */
25 
26 #ifdef USING_PCH
27 #	include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #	include <config.h>
31 #endif
32 
33 #include "timegather.h"
34 #include "value_desc.h"
35 
36 #include <synfig/general.h>
37 
38 #include <synfig/layers/layer_pastecanvas.h>
39 
40 #include <synfigapp/localization.h>
41 
42 #endif
43 
44 /* === U S I N G =========================================================== */
45 
46 using namespace std;
47 using namespace etl;
48 using namespace synfig;
49 using namespace synfigapp;
50 
51 /* === M A C R O S ========================================================= */
52 
53 /* === G L O B A L S ======================================================= */
54 
55 /* === P R O C E D U R E S ================================================= */
56 
57 /* === M E T H O D S ======================================================= */
58 
59 /* === E N T R Y P O I N T ================================================= */
60 
61 //! Definitions for build a list of accurate valuenode references
62 
insert(synfig::ValueNode_Animated::Handle v,synfig::Waypoint w,synfig::Real time_dilation)63 void synfigapp::timepoints_ref::insert(synfig::ValueNode_Animated::Handle v, synfig::Waypoint w, synfig::Real time_dilation)
64 {
65 	ValueBaseTimeInfo	vt;
66 	vt.val = v;
67 	vt.time_dilation = time_dilation;
68 
69 	waytracker::iterator i = waypointbiglist.find(vt);
70 
71 	if(i != waypointbiglist.end())
72 	{
73 		i->waypoints.insert(w);
74 	}else
75 	{
76 		vt.waypoints.insert(w);
77 		waypointbiglist.insert(vt);
78 	}
79 }
80 
insert(synfigapp::ValueDesc v,synfig::Activepoint a,synfig::Real time_dilation)81 void synfigapp::timepoints_ref::insert(synfigapp::ValueDesc v, synfig::Activepoint a, synfig::Real time_dilation)
82 {
83 	ActiveTimeInfo	vt;
84 	vt.val = v;
85 	vt.time_dilation = time_dilation;
86 
87 	acttracker::iterator i = actpointbiglist.find(vt);
88 
89 	if(i != actpointbiglist.end())
90 	{
91 		i->activepoints.insert(a);
92 		/*{ //if it fails...
93 			synfig::info("!!!!For some reason it wasn't able to insert the activepoint in the list (%s,%.4lg)",
94 							a.state?"true":"false", (double)a.time);
95 		}*/
96 	}else
97 	{
98 		vt.activepoints.insert(a);
99 		actpointbiglist.insert(vt);
100 		//synfig::info("Insert new activept list for valdesc");
101 	}
102 }
103 
104 //recursion functions
recurse_canvas(synfig::Canvas::Handle h,const std::set<Time> & tlist,timepoints_ref & vals,synfig::Time time_offset,synfig::Real time_dilation)105 void synfigapp::recurse_canvas(synfig::Canvas::Handle h, const std::set<Time> &tlist,
106 								timepoints_ref &vals, synfig::Time time_offset, synfig::Real time_dilation)
107 {
108 
109 	//synfig::info("Canvas...\n Recurse through layers");
110 	// iterate through the layers
111 
112 	synfig::Canvas::iterator i = h->begin(), end = h->end();
113 
114 	for(; i != end; ++i)
115 	{
116 		const Node::time_set &tset = (*i)->get_times();
117 		if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset,time_dilation))
118 		{
119 			recurse_layer(*i,tlist,vals,time_offset,time_dilation);
120 		}
121 	}
122 }
123 
recurse_layer(synfig::Layer::Handle h,const std::set<Time> & tlist,timepoints_ref & vals,synfig::Time time_offset,synfig::Real time_dilation)124 void synfigapp::recurse_layer(synfig::Layer::Handle h, const std::set<Time> &tlist,
125 								timepoints_ref &vals, synfig::Time time_offset, synfig::Real time_dilation)
126 {
127 	// iterate through the layers
128 	//check for special case of paste canvas
129 	etl::handle<synfig::Layer_PasteCanvas> p = etl::handle<synfig::Layer_PasteCanvas>::cast_dynamic(h);
130 
131 	//synfig::info("Layer...");
132 
133 	if(p)
134 	{
135 		//synfig::info("We are a paste canvas so go into that");
136 		//recurse into the canvas
137 		const synfig::Node::time_set &tset = p->get_sub_canvas()->get_times();
138 		synfig::Real subcanvas_time_dilation(p->get_time_dilation());
139 		synfig::Time subcanvas_time_offset(time_offset * subcanvas_time_dilation + p->get_time_offset());
140 		subcanvas_time_dilation *= time_dilation;
141 
142 		if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),subcanvas_time_offset,subcanvas_time_dilation))
143 			recurse_canvas(p->get_sub_canvas(),tlist,vals,subcanvas_time_offset,subcanvas_time_dilation);
144 	}
145 
146 	//check all the valuenodes regardless...
147 	//synfig::info("Recurse all valuenodes");
148 	synfig::Layer::DynamicParamList::const_iterator 	i = h->dynamic_param_list().begin(),
149 													end = h->dynamic_param_list().end();
150 	for(; i != end; ++i)
151 	{
152 		const synfig::Node::time_set &tset = i->second->get_times();
153 
154 		if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset,time_dilation))
155 		{
156 			recurse_valuedesc(ValueDesc(h,i->first),tlist,vals,time_offset,time_dilation);
157 		}
158 	}
159 }
160 
161 template < typename IT, typename CMP >
sorted(IT i,IT end,const CMP & cmp=CMP ())162 static bool sorted(IT i,IT end, const CMP &cmp = CMP())
163 {
164 	if(i == end) return true;
165 
166 	for(IT last = i++; i != end; last = i++)
167 	{
168 		if(!cmp(*last,*i))
169 			return false;
170 	}
171 
172 	return true;
173 }
174 
recurse_valuedesc(synfigapp::ValueDesc h,const std::set<Time> & tlist,timepoints_ref & vals,synfig::Time time_offset,synfig::Real time_dilation)175 void synfigapp::recurse_valuedesc(synfigapp::ValueDesc h, const std::set<Time> &tlist,
176 								timepoints_ref &vals, synfig::Time time_offset, synfig::Real time_dilation)
177 {
178 	//special cases for Animated, DynamicList, and Linkable
179 
180 	//synfig::info("ValueBasenode... %p, %s", h.get_value_node().get(),typeid(*h.get_value_node()).name());
181 
182 
183 	//animated case
184 	{
185 		synfig::ValueNode_Animated::Handle p = synfig::ValueNode_Animated::Handle::cast_dynamic(h.get_value_node());
186 
187 		if(p)
188 		{
189 			//loop through and determine which waypoint we will need to reference
190 			const synfig::WaypointList &w = p->waypoint_list();
191 
192 			synfig::WaypointList::const_iterator i = w.begin(),
193 												end = w.end();
194 
195 			std::set<Time>::const_iterator		j = tlist.begin(),
196 												jend = tlist.end();
197 			for(; i != end && j != jend;)
198 			{
199 				//synfig::info("tpair t(%.3f) = %.3f", (float)*j, (float)(i->get_time()));
200 
201 				if((*j*time_dilation+time_offset).is_equal(i->get_time()))
202 				{
203 					vals.insert(p,*i,time_dilation);
204 					++i,++j;
205 				}else if(*i < *j*time_dilation+time_offset)
206 				{
207 					++i;
208 				}else ++j;
209 			}
210 			return;
211 		}
212 	}
213 
214 	//parent dynamiclist case - just for active points for that object...
215 	if(h.parent_is_value_node())
216 	{
217 		synfig::ValueNode_DynamicList::Handle p = synfig::ValueNode_DynamicList::Handle::cast_dynamic(h.get_parent_value_node());
218 
219 		if(p)
220 		{
221 			int index = h.get_index();
222 
223 			//check all the active points in each list...
224 			const synfig::ActivepointList &a = p->list[index].timing_info;
225 
226 			//synfig::info("Our parent = dynamic list, searching in %d activepts",a.size());
227 
228 			std::set<Time>::const_iterator			i = tlist.begin(),
229 													end = tlist.end();
230 
231 			synfig::ActivepointList::const_iterator 	j = a.begin(),
232 													jend = a.end();
233 
234 			for(; j != jend && i != end;)
235 			{
236 				double it = *i*time_dilation+time_offset;
237 				double jt = j->get_time();
238 				double diff = (double)(it - jt);
239 
240 				//synfig::info("\ttpair match(%.4lg) - %.4lg (diff = %lg",it,jt,diff);
241 
242 				//
243 				if(abs(diff) < (double)Time::epsilon())
244 				{
245 					//synfig::info("\tActivepoint to add being referenced (%x,%s,%.4lg)",
246 					//				(int)j->get_uid(),j->state?"true":"false", (double)j->time);
247 					vals.insert(ValueDesc(p,index),*j,time_dilation);
248 					++i,++j;
249 				}else if(it < jt)
250 				{
251 					++i;
252 					//synfig::info("\tIncrementing time");
253 				}
254 				else
255 				{
256 					++j;
257 					//synfig::info("\tIncrementing actpt");
258 				}
259 			}
260 		}
261 	}
262 
263 	//dynamiclist case - we must still make sure that we read from the list entries the time values
264 	//						because just the linked valuenodes will not do that
265 	{
266 		synfig::ValueNode_DynamicList::Handle p = synfig::ValueNode_DynamicList::Handle::cast_dynamic(h.get_value_node());
267 
268 		if(p)
269 		{
270 			//synfig::info("Process dynamic list valuenode");
271 			int index = 0;
272 
273 			std::vector<synfig::ValueNode_DynamicList::ListEntry>::const_iterator
274 							i = p->list.begin(),
275 							end = p->list.end();
276 
277 			for(; i != end; ++i, ++index)
278 			{
279 				const Node::time_set &tset = i->get_times();
280 
281 				if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset,time_dilation))
282 				{
283 					recurse_valuedesc(ValueDesc(p,index),tlist,vals,time_offset,time_dilation);
284 				}
285 			}
286 			return;
287 		}
288 	}
289 
290 	//the linkable case...
291 	{
292 		etl::handle<synfig::LinkableValueNode> p = etl::handle<synfig::LinkableValueNode>::cast_dynamic(h.get_value_node());
293 
294 		if(p)
295 		{
296 			//synfig::info("Process Linkable ValueBasenode");
297 			int i = 0, size = p->link_count();
298 
299 			for(; i < size; ++i)
300 			{
301 				ValueNode::Handle v = p->get_link(i);
302 				const Node::time_set &tset = v->get_times();
303 
304 				if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset,time_dilation))
305 				{
306 					recurse_valuedesc(ValueDesc(p,i),tlist,vals,time_offset,time_dilation);
307 				}
308 			}
309 		}
310 	}
311 }
312