my log
[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: timegather.cpp,v 1.1.1.1 2005/01/07 03:34:37 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2004 Adrian Bentley
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
14 **      You may not copy, print, publish, or in any
15 **      other way distribute this software without
16 **      a prior written agreement with
17 **      the copyright holder.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "timegather.h"
32 #include "value_desc.h"
33
34 #include <synfig/layer_pastecanvas.h>
35
36 #endif
37
38 /* === U S I N G =========================================================== */
39
40 using namespace std;
41 using namespace etl;
42 using namespace synfig;
43 using namespace synfigapp;
44
45 /* === M A C R O S ========================================================= */
46
47 /* === G L O B A L S ======================================================= */
48
49 /* === P R O C E D U R E S ================================================= */
50
51 /* === M E T H O D S ======================================================= */
52
53 /* === E N T R Y P O I N T ================================================= */
54
55 //! Definitions for build a list of accurate valuenode references
56
57 void synfigapp::timepoints_ref::insert(synfig::ValueNode_Animated::Handle v, synfig::Waypoint w)
58 {
59         ValueBaseTimeInfo       vt;
60         vt.val = v;
61         
62         waytracker::iterator i = waypointbiglist.find(vt);
63         
64         if(i != waypointbiglist.end())
65         {
66                 i->waypoints.insert(w);
67         }else
68         {
69                 vt.waypoints.insert(w);
70                 waypointbiglist.insert(vt);
71         }
72 }
73
74 void synfigapp::timepoints_ref::insert(synfigapp::ValueDesc v, synfig::Activepoint a)
75 {
76         ActiveTimeInfo  vt;
77         vt.val = v;
78         
79         acttracker::iterator i = actpointbiglist.find(vt);
80         
81         if(i != actpointbiglist.end())
82         {
83                 i->activepoints.insert(a);
84                 /*{ //if it fails...
85                         synfig::info("!!!!For some reason it wasn't able to insert the activepoint in the list (%s,%.4lg)",
86                                                         a.state?"true":"false", (double)a.time);
87                 }*/
88         }else
89         {
90                 vt.activepoints.insert(a);
91                 actpointbiglist.insert(vt);
92                 //synfig::info("Insert new activept list for valdesc");
93         }
94 }
95
96 //recursion functions
97 void synfigapp::recurse_canvas(synfig::Canvas::Handle h, const std::set<Time> &tlist, 
98                                                                 timepoints_ref &vals)
99 {
100         
101         //synfig::info("Canvas...\n Recurse through layers");
102         // iterate through the layers
103
104         synfig::Canvas::iterator i = h->begin(), end = h->end();
105
106         for(; i != end; ++i)
107         {
108                 const Node::time_set &tset = (*i)->get_times();
109                 if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end()))
110                 {
111                         recurse_layer(*i,tlist,vals);
112                 }
113         }
114 }
115
116 void synfigapp::recurse_layer(synfig::Layer::Handle h, const std::set<Time> &tlist, 
117                                                                 timepoints_ref &vals)
118 {
119         // iterate through the layers
120         //check for special case of paste canvas
121         etl::handle<synfig::Layer_PasteCanvas> p = etl::handle<synfig::Layer_PasteCanvas>::cast_dynamic(h);
122         
123         //synfig::info("Layer...");
124         
125         if(p)
126         {
127                 //synfig::info("We are a paste canvas so go into that");
128                 //recurse into the canvas
129                 const synfig::Node::time_set &tset = p->get_sub_canvas()->get_times();
130                 
131                 if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end()))
132                 {
133                         //we have to offset the times so it won't wreck havoc if the canvas is imported more than once...
134                         // and so we get correct results when offsets are present
135                         std::set<Time>  tlistoff;                       
136                         std::set<Time>::iterator i = tlist.begin(), end = tlist.end();
137                         for(; i != end; ++i)
138                         {
139                                 tlistoff.insert(*i - p->get_time_offset());
140                         }
141                         
142                         recurse_canvas(p->get_sub_canvas(),tlist,vals);
143                 }
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()))
155                 {
156                         recurse_valuedesc(ValueDesc(h,i->first),tlist,vals);
157                 }
158         }
159 }
160
161 template < typename IT, typename 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
175 void synfigapp::recurse_valuedesc(synfigapp::ValueDesc h, const std::set<Time> &tlist, 
176                                                                 timepoints_ref &vals)
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->is_equal(i->get_time()))
202                                 {
203                                         vals.insert(p,*i);
204                                         ++i,++j;
205                                 }else if(*i < *j) 
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;
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);
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()))
282                                 {
283                                         recurse_valuedesc(ValueDesc(p,index),tlist,vals);
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()))
305                                 {
306                                         recurse_valuedesc(ValueDesc(p,i),tlist,vals);
307                                 }
308                         }
309                 }
310         }
311 }