X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-core%2Ftrunk%2Fsrc%2Fsynfig%2Fcontext.cpp;h=38e0f671684321f872798f77cc8c1f1d9872c545;hb=756c0d29ac1742f231e6615f9a577e574e35a4af;hp=247dac191609970935477574f1310b9444f20daf;hpb=51ad9324b6978ff2b7bf607b2af7727201f667e0;p=synfig.git diff --git a/synfig-core/trunk/src/synfig/context.cpp b/synfig-core/trunk/src/synfig/context.cpp index 247dac1..38e0f67 100644 --- a/synfig-core/trunk/src/synfig/context.cpp +++ b/synfig-core/trunk/src/synfig/context.cpp @@ -6,6 +6,7 @@ ** ** \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 @@ -31,6 +32,7 @@ #include "context.h" #include "layer.h" +#include "layer_composite.h" #include "string.h" #include "vector.h" #include "color.h" @@ -48,8 +50,8 @@ using namespace synfig; /* === M A C R O S ========================================================= */ -//#define SYNFIG_PROFILE_LAYERS -//#define SYNFIG_DEBUG_LAYERS +// #define SYNFIG_PROFILE_LAYERS +// #define SYNFIG_DEBUG_LAYERS /* === G L O B A L S ======================================================= */ @@ -77,8 +79,7 @@ _print_profile_report() synfig::info("Total Time: %f seconds", total_time); synfig::info("<<<< End of Profile Report"); } - -#endif +#endif // SYNFIG_PROFILE_LAYERS /* === P R O C E D U R E S ================================================= */ @@ -165,7 +166,7 @@ Context::get_full_bounding_rect()const bool Context::accelerated_render(Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const { - #ifdef SYNFIG_PROFILE_LAYERS +#ifdef SYNFIG_PROFILE_LAYERS String layer_name(curr_layer); //sum the pre-work done by layer above us... (curr_layer is layer above us...) @@ -175,63 +176,112 @@ Context::accelerated_render(Surface *surface,int quality, const RendDesc &rendde //if(run_table.count(curr_layer))run_table[curr_layer]++; // else run_table[curr_layer]=1; } - #endif +#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 composite; Context context(*this); + for(;!(context)->empty();++context) { - // If we are not active - // then move on to next layer + // If we are not active then move on to next layer if(!(*context)->active()) continue; const Rect layer_bounds((*context)->get_bounding_rect()); - - // If the box area is less than zero - // then move on to next layer - if(layer_bounds.area()<=0.0000000000001) - continue; - - // If the boxes do not intersect - // then move on to next layer - if(!(layer_bounds && bbox)) + composite = etl::handle::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()) + 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 +#endif // SYNFIG_DEBUG_LAYERS surface->set_wh(renddesc.get_w(),renddesc.get_h()); surface->clear(); - #ifdef SYNFIG_PROFILE_LAYERS +#ifdef SYNFIG_PROFILE_LAYERS profile_timer.reset(); - #endif +#endif // SYNFIG_PROFILE_LAYERS return true; } #ifdef SYNFIG_DEBUG_LAYERS synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str()); -#endif +#endif // SYNFIG_DEBUG_LAYERS try { RWLock::ReaderLock lock((*context)->get_rw_lock()); - #ifdef SYNFIG_PROFILE_LAYERS - +#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(); // + - bool ret((*context)->accelerated_render(context+1,surface,quality,renddesc, cb)); +#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]++; @@ -243,21 +293,19 @@ Context::accelerated_render(Surface *surface,int quality, const RendDesc &rendde //print out the table it we're done... if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear(); profile_timer.reset(); //+ - return ret; - #else - return (*context)->accelerated_render(context+1,surface,quality,renddesc, cb); - #endif +#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 +#else // _DEBUG ++context; return context.accelerated_render(surface, quality, renddesc, cb); -#endif +#endif // _DEBUG } catch(...) { @@ -272,9 +320,13 @@ Context::set_time(Time time)const Context context(*this); while(!(context)->empty()) { - // If this layer is active, then go - // ahead and break out of the loop - if((*context)->active() && !(*context)->dirty_time_.is_equal(time)) + // 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 @@ -286,7 +338,7 @@ Context::set_time(Time time)const // If this layer isn't defined, just return if((context)->empty()) return; - // Set up a wrter lock + // 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_); @@ -308,7 +360,7 @@ Context::set_time(Time time)const } void -Context::set_time(Time time,const Vector &pos)const +Context::set_time(Time time,const Vector &/*pos*/)const { set_time(time); /*