+++ /dev/null
-/* === S Y N F I G ========================================================= */
-/*! \file context.cpp
-** \brief Template File
-**
-** $Id$
-**
-** \legal
-** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-** Copyright (c) 2008 Chris Moore
-**
-** This package is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License as
-** published by the Free Software Foundation; either version 2 of
-** the License, or (at your option) any later version.
-**
-** This package is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** General Public License for more details.
-** \endlegal
-*/
-/* ========================================================================= */
-
-/* === H E A D E R S ======================================================= */
-
-#ifdef USING_PCH
-# include "pch.h"
-#else
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "context.h"
-#include "layer.h"
-#include "layer_composite.h"
-#include "string.h"
-#include "vector.h"
-#include "color.h"
-#include "surface.h"
-#include "renddesc.h"
-#include "valuenode.h"
-
-#endif
-
-/* === U S I N G =========================================================== */
-
-using namespace std;
-using namespace etl;
-using namespace synfig;
-
-/* === M A C R O S ========================================================= */
-
-// #define SYNFIG_PROFILE_LAYERS
-// #define SYNFIG_DEBUG_LAYERS
-
-/* === G L O B A L S ======================================================= */
-
-#ifdef SYNFIG_PROFILE_LAYERS
-#include <ETL/clock>
-static int depth(0);
-static std::map<String,float> time_table;
-static std::map<String,int> run_table;
-static etl::clock profile_timer;
-static String curr_layer;
-static void
-_print_profile_report()
-{
- synfig::info(">>>> Profile Report: (Times are in msecs)");
- std::map<String,float>::iterator iter;
- float total_time(0);
- for(iter=time_table.begin();iter!=time_table.end();++iter)
- {
- String layer(iter->first);
- float time(iter->second);
- int runs(run_table[layer]);
- total_time+=time;
- synfig::info(" Layer \"%s\",\tExecs: %03d, Avg Time: %05.1f, Total Time: %05.1f",layer.c_str(),runs,time/runs*1000,time*1000);
- }
- synfig::info("Total Time: %f seconds", total_time);
- synfig::info("<<<< End of Profile Report");
-}
-#endif // SYNFIG_PROFILE_LAYERS
-
-/* === P R O C E D U R E S ================================================= */
-
-/* === M E T H O D S ======================================================= */
-
-Color
-Context::get_color(const Point &pos)const
-{
- Context context(*this);
-
- while(!context->empty())
- {
- // If this layer is active, then go
- // ahead and break out of the loop
- if((*context)->active())
- break;
-
- // Otherwise, we want to keep searching
- // till we find either an active layer,
- // or the end of the layer list
- ++context;
- }
-
- // If this layer isn't defined, return alpha
- if((context)->empty()) return Color::alpha();
-
- RWLock::ReaderLock lock((*context)->get_rw_lock());
-
- return (*context)->get_color(context+1, pos);
-}
-
-Rect
-Context::get_full_bounding_rect()const
-{
- Context context(*this);
-
- while(!context->empty())
- {
- // If this layer is active, then go
- // ahead and break out of the loop
- if((*context)->active())
- break;
-
- // Otherwise, we want to keep searching
- // till we find either an active layer,
- // or the end of the layer list
- ++context;
- }
-
- // If this layer isn't defined, return zero-sized rectangle
- if(context->empty()) return Rect::zero();
-
- return (*context)->get_full_bounding_rect(context+1);
-}
-
-
-/* Profiling will go like this:
- Profile start = +, stop = -
-
- +
- -
-
- time diff is recorded
-
- to get the independent times we need to break at the one inside and record etc...
- so it looks more like this:
-
- +
- -
- +
- -
- +
- ...
- -
- +
- -
- +
- -
-
- at each minus we must record all the info for that which we are worried about...
- each layer can do work before or after the other work is done... so both values must be recorded...
-*/
-
-bool
-Context::accelerated_render(Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
-{
-#ifdef SYNFIG_PROFILE_LAYERS
- String layer_name(curr_layer);
-
- //sum the pre-work done by layer above us... (curr_layer is layer above us...)
- if(depth>0)
- {
- time_table[curr_layer]+=profile_timer();
- //if(run_table.count(curr_layer))run_table[curr_layer]++;
- // else run_table[curr_layer]=1;
- }
-#endif // SYNFIG_PROFILE_LAYERS
-
- const Rect bbox(renddesc.get_rect());
-
- // this is going to be set to true if this layer contributes
- // nothing, but it's a straight blend with non-zero amount, and so
- // it has an effect anyway
- bool straight_and_empty = false;
- etl::handle<Layer_Composite> composite;
- Context context(*this);
-
- for(;!(context)->empty();++context)
- {
- // If we are not active then move on to next layer
- if(!(*context)->active())
- continue;
-
- const Rect layer_bounds((*context)->get_bounding_rect());
- composite = etl::handle<Layer_Composite>::cast_dynamic(*context);
-
- // If the box area is less than zero or the boxes do not
- // intersect then move on to next layer, unless the layer is
- // using a straight blend and has a non-zero amount, in which
- // case it will still affect the result
- if(layer_bounds.area() <= 0.0000000000001 || !(layer_bounds && bbox))
- {
- if (composite &&
- Color::is_straight(composite->get_blend_method()) &&
- composite->get_amount() != 0.0f)
- {
- straight_and_empty = true;
- break;
- }
- continue;
- }
-
- // If this layer has Straight as the blend method and amount
- // is 1.0, and the layer doesn't depend on its context, then
- // we don't want to render the context
- if (composite &&
- composite->get_blend_method() == Color::BLEND_STRAIGHT &&
- composite->get_amount() == 1.0f &&
- !composite->reads_context())
- {
- Layer::Handle layer = *context;
- while (!context->empty()) context++; // skip the context
- return layer->accelerated_render(context,surface,quality,renddesc, cb);
- }
-
- // Break out of the loop--we have found a good layer
- break;
- }
-
- // If this layer isn't defined, return alpha
- if (context->empty() || (straight_and_empty && composite->get_amount() == 1.0f))
- {
-#ifdef SYNFIG_DEBUG_LAYERS
- synfig::info("Context::accelerated_render(): Hit end of list");
-#endif // SYNFIG_DEBUG_LAYERS
- surface->set_wh(renddesc.get_w(),renddesc.get_h());
- surface->clear();
-#ifdef SYNFIG_PROFILE_LAYERS
- profile_timer.reset();
-#endif // SYNFIG_PROFILE_LAYERS
- return true;
- }
-
-#ifdef SYNFIG_DEBUG_LAYERS
- synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str());
-#endif // SYNFIG_DEBUG_LAYERS
-
- try {
- RWLock::ReaderLock lock((*context)->get_rw_lock());
-
-#ifdef SYNFIG_PROFILE_LAYERS
- //go down one layer :P
- depth++;
- curr_layer=(*context)->get_name(); //make sure the layer inside is referring to the correct layer outside
- profile_timer.reset(); // +
-#endif // SYNFIG_PROFILE_LAYERS
-
- bool ret;
-
- // this layer doesn't draw anything onto the canvas we're
- // rendering, but it uses straight blending, so we need to render
- // the stuff under us and then blit transparent pixels over it
- // using the appropriate 'amount'
- if (straight_and_empty)
- {
- if ((ret = Context((context+1)).accelerated_render(surface,quality,renddesc,cb)))
- {
- Surface clearsurface;
- clearsurface.set_wh(renddesc.get_w(),renddesc.get_h());
- clearsurface.clear();
-
- Surface::alpha_pen apen(surface->begin());
- apen.set_alpha(composite->get_amount());
- apen.set_blend_method(composite->get_blend_method());
-
- clearsurface.blit_to(apen);
- }
- }
- else
- ret = (*context)->accelerated_render(context+1,surface,quality,renddesc, cb);
-
-#ifdef SYNFIG_PROFILE_LAYERS
- //post work for the previous layer
- time_table[curr_layer]+=profile_timer(); //-
- if(run_table.count(curr_layer))run_table[curr_layer]++;
- else run_table[curr_layer]=1;
-
- depth--;
- curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
-
- //print out the table it we're done...
- if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
- profile_timer.reset(); //+
-#endif // SYNFIG_PROFILE_LAYERS
-
- return ret;
- }
- catch(std::bad_alloc)
- {
- synfig::error("Context::accelerated_render(): Layer \"%s\" threw a bad_alloc exception!",(*context)->get_name().c_str());
-#ifdef _DEBUG
- return false;
-#else // _DEBUG
- ++context;
- return context.accelerated_render(surface, quality, renddesc, cb);
-#endif // _DEBUG
- }
- catch(...)
- {
- synfig::error("Context::accelerated_render(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
- throw;
- }
-}
-
-void
-Context::set_time(Time time)const
-{
- Context context(*this);
- while(!(context)->empty())
- {
- // If this layer is active, and
- // it either isn't already set to the given time or
- // it's a time loop layer,
- // then break out of the loop and set its time
- if((*context)->active() &&
- (!(*context)->dirty_time_.is_equal(time) ||
- (*context)->get_name() == "timeloop"))
- break;
-
- // Otherwise, we want to keep searching
- // till we find either an active layer,
- // or the end of the layer list
- ++context;
- }
-
- // If this layer isn't defined, just return
- if((context)->empty()) return;
-
- // Set up a writer lock
- RWLock::WriterLock lock((*context)->get_rw_lock());
-
- //synfig::info("%s: dirty_time=%f",(*context)->get_name().c_str(),(float)(*context)->dirty_time_);
- //synfig::info("%s: time=%f",(*context)->get_name().c_str(),(float)time);
-
- {
- Layer::ParamList params;
- Layer::DynamicParamList::const_iterator iter;
-
- for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
- params[iter->first]=(*iter->second)(time);
-
- (*context)->set_param_list(params);
-
- (*context)->set_time(context+1,time);
- (*context)->dirty_time_=time;
-
- }
-}
-
-void
-Context::set_time(Time time,const Vector &/*pos*/)const
-{
- set_time(time);
-/*
- Context context(*this);
- while(!(context)->empty())
- {
- // If this layer is active, then go
- // ahead and break out of the loop
- if((*context)->active())
- break;
-
- // Otherwise, we want to keep searching
- // till we find either an active layer,
- // or the end of the layer list
- ++context;
- }
-
- // If this layer isn't defined, just return
- if((context)->empty()) return;
-
- else
- {
- Layer::ParamList params;
- Layer::DynamicParamList::const_iterator iter;
-
- for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
- params[iter->first]=(*iter->second)(time);
-
- (*context)->set_param_list(params);
-
- (*context)->set_time(context+1,time,pos);
- }
-*/
-}
-
-etl::handle<Layer>
-Context::hit_check(const Point &pos)const
-{
- Context context(*this);
-
- while(!context->empty())
- {
- // If this layer is active, then go
- // ahead and break out of the loop
- if((*context)->active())
- break;
-
- // Otherwise, we want to keep searching
- // till we find either an active layer,
- // or the end of the layer list
- ++context;
- }
-
- // If this layer isn't defined, return an empty handle
- if((context)->empty()) return 0;
-
- return (*context)->hit_check(context+1, pos);
-}