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