1 /* === S Y N F I G ========================================================= */
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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.
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.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
34 #include "layer_composite.h"
40 #include "valuenode.h"
44 /* === U S I N G =========================================================== */
48 using namespace synfig;
50 /* === M A C R O S ========================================================= */
52 // #define SYNFIG_PROFILE_LAYERS
53 // #define SYNFIG_DEBUG_LAYERS
55 /* === G L O B A L S ======================================================= */
57 #ifdef SYNFIG_PROFILE_LAYERS
60 static std::map<String,float> time_table;
61 static std::map<String,int> run_table;
62 static etl::clock profile_timer;
63 static String curr_layer;
65 _print_profile_report()
67 synfig::info(">>>> Profile Report: (Times are in msecs)");
68 std::map<String,float>::iterator iter;
70 for(iter=time_table.begin();iter!=time_table.end();++iter)
72 String layer(iter->first);
73 float time(iter->second);
74 int runs(run_table[layer]);
76 synfig::info(" Layer \"%s\",\tExecs: %03d, Avg Time: %05.1f, Total Time: %05.1f",layer.c_str(),runs,time/runs*1000,time*1000);
78 synfig::info("Total Time: %f seconds", total_time);
79 synfig::info("<<<< End of Profile Report");
81 #endif // SYNFIG_PROFILE_LAYERS
83 /* === P R O C E D U R E S ================================================= */
85 /* === M E T H O D S ======================================================= */
88 Context::get_color(const Point &pos)const
90 Context context(*this);
92 while(!context->empty())
94 // If this layer is active, then go
95 // ahead and break out of the loop
96 if((*context)->active())
99 // Otherwise, we want to keep searching
100 // till we find either an active layer,
101 // or the end of the layer list
105 // If this layer isn't defined, return alpha
106 if((context)->empty()) return Color::alpha();
108 RWLock::ReaderLock lock((*context)->get_rw_lock());
110 return (*context)->get_color(context+1, pos);
114 Context::get_full_bounding_rect()const
116 Context context(*this);
118 while(!context->empty())
120 // If this layer is active, then go
121 // ahead and break out of the loop
122 if((*context)->active())
125 // Otherwise, we want to keep searching
126 // till we find either an active layer,
127 // or the end of the layer list
131 // If this layer isn't defined, return zero-sized rectangle
132 if(context->empty()) return Rect::zero();
134 return (*context)->get_full_bounding_rect(context+1);
138 /* Profiling will go like this:
139 Profile start = +, stop = -
144 time diff is recorded
146 to get the independent times we need to break at the one inside and record etc...
147 so it looks more like this:
161 at each minus we must record all the info for that which we are worried about...
162 each layer can do work before or after the other work is done... so both values must be recorded...
166 Context::accelerated_render(Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
168 #ifdef SYNFIG_PROFILE_LAYERS
169 String layer_name(curr_layer);
171 //sum the pre-work done by layer above us... (curr_layer is layer above us...)
174 time_table[curr_layer]+=profile_timer();
175 //if(run_table.count(curr_layer))run_table[curr_layer]++;
176 // else run_table[curr_layer]=1;
178 #endif // SYNFIG_PROFILE_LAYERS
180 const Rect bbox(renddesc.get_rect());
182 // this is going to be set to true if this layer contributes
183 // nothing, but it's a straight blend with non-zero amount, and so
184 // it has an effect anyway
185 bool straight_and_empty = false;
186 etl::handle<Layer_Composite> composite;
187 Context context(*this);
189 for(;!(context)->empty();++context)
191 // If we are not active then move on to next layer
192 if(!(*context)->active())
195 const Rect layer_bounds((*context)->get_bounding_rect());
196 composite = etl::handle<Layer_Composite>::cast_dynamic(*context);
198 // If the box area is less than zero or the boxes do not
199 // intersect then move on to next layer, unless the layer is
200 // using a straight blend and has a non-zero amount, in which
201 // case it will still affect the result
202 if(layer_bounds.area() <= 0.0000000000001 || !(layer_bounds && bbox))
205 Color::is_straight(composite->get_blend_method()) &&
206 composite->get_amount() != 0.0f)
208 straight_and_empty = true;
214 // If this layer has Straight as the blend method and amount
215 // is 1.0, and the layer doesn't depend on its context, then
216 // we don't want to render the context
218 composite->get_blend_method() == Color::BLEND_STRAIGHT &&
219 composite->get_amount() == 1.0f &&
220 !composite->reads_context())
222 Layer::Handle layer = *context;
223 while (!context->empty()) context++; // skip the context
224 return layer->accelerated_render(context,surface,quality,renddesc, cb);
227 // Break out of the loop--we have found a good layer
231 // If this layer isn't defined, return alpha
232 if (context->empty() || (straight_and_empty && composite->get_amount() == 1.0f))
234 #ifdef SYNFIG_DEBUG_LAYERS
235 synfig::info("Context::accelerated_render(): Hit end of list");
236 #endif // SYNFIG_DEBUG_LAYERS
237 surface->set_wh(renddesc.get_w(),renddesc.get_h());
239 #ifdef SYNFIG_PROFILE_LAYERS
240 profile_timer.reset();
241 #endif // SYNFIG_PROFILE_LAYERS
245 #ifdef SYNFIG_DEBUG_LAYERS
246 synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str());
247 #endif // SYNFIG_DEBUG_LAYERS
250 RWLock::ReaderLock lock((*context)->get_rw_lock());
252 #ifdef SYNFIG_PROFILE_LAYERS
253 //go down one layer :P
255 curr_layer=(*context)->get_name(); //make sure the layer inside is referring to the correct layer outside
256 profile_timer.reset(); // +
257 #endif // SYNFIG_PROFILE_LAYERS
261 // this layer doesn't draw anything onto the canvas we're
262 // rendering, but it uses straight blending, so we need to render
263 // the stuff under us and then blit transparent pixels over it
264 // using the appropriate 'amount'
265 if (straight_and_empty)
267 if ((ret = Context((context+1)).accelerated_render(surface,quality,renddesc,cb)))
269 Surface clearsurface;
270 clearsurface.set_wh(renddesc.get_w(),renddesc.get_h());
271 clearsurface.clear();
273 Surface::alpha_pen apen(surface->begin());
274 apen.set_alpha(composite->get_amount());
275 apen.set_blend_method(composite->get_blend_method());
277 clearsurface.blit_to(apen);
281 ret = (*context)->accelerated_render(context+1,surface,quality,renddesc, cb);
283 #ifdef SYNFIG_PROFILE_LAYERS
284 //post work for the previous layer
285 time_table[curr_layer]+=profile_timer(); //-
286 if(run_table.count(curr_layer))run_table[curr_layer]++;
287 else run_table[curr_layer]=1;
290 curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
292 //print out the table it we're done...
293 if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
294 profile_timer.reset(); //+
295 #endif // SYNFIG_PROFILE_LAYERS
299 catch(std::bad_alloc)
301 synfig::error("Context::accelerated_render(): Layer \"%s\" threw a bad_alloc exception!",(*context)->get_name().c_str());
306 return context.accelerated_render(surface, quality, renddesc, cb);
311 synfig::error("Context::accelerated_render(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
317 Context::set_time(Time time)const
319 Context context(*this);
320 while(!(context)->empty())
322 // If this layer is active, and
323 // it either isn't already set to the given time or
324 // it's a time loop layer,
325 // then break out of the loop and set its time
326 if((*context)->active() &&
327 (!(*context)->dirty_time_.is_equal(time) ||
328 (*context)->get_name() == "timeloop"))
331 // Otherwise, we want to keep searching
332 // till we find either an active layer,
333 // or the end of the layer list
337 // If this layer isn't defined, just return
338 if((context)->empty()) return;
340 // Set up a writer lock
341 RWLock::WriterLock lock((*context)->get_rw_lock());
343 //synfig::info("%s: dirty_time=%f",(*context)->get_name().c_str(),(float)(*context)->dirty_time_);
344 //synfig::info("%s: time=%f",(*context)->get_name().c_str(),(float)time);
347 Layer::ParamList params;
348 Layer::DynamicParamList::const_iterator iter;
350 for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
351 params[iter->first]=(*iter->second)(time);
353 (*context)->set_param_list(params);
355 (*context)->set_time(context+1,time);
356 (*context)->dirty_time_=time;
362 Context::set_time(Time time,const Vector &/*pos*/)const
366 Context context(*this);
367 while(!(context)->empty())
369 // If this layer is active, then go
370 // ahead and break out of the loop
371 if((*context)->active())
374 // Otherwise, we want to keep searching
375 // till we find either an active layer,
376 // or the end of the layer list
380 // If this layer isn't defined, just return
381 if((context)->empty()) return;
385 Layer::ParamList params;
386 Layer::DynamicParamList::const_iterator iter;
388 for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
389 params[iter->first]=(*iter->second)(time);
391 (*context)->set_param_list(params);
393 (*context)->set_time(context+1,time,pos);
399 Context::hit_check(const Point &pos)const
401 Context context(*this);
403 while(!context->empty())
405 // If this layer is active, then go
406 // ahead and break out of the loop
407 if((*context)->active())
410 // Otherwise, we want to keep searching
411 // till we find either an active layer,
412 // or the end of the layer list
416 // If this layer isn't defined, return an empty handle
417 if((context)->empty()) return 0;
419 return (*context)->hit_check(context+1, pos);