Re-enable the 'alpha brighten' and 'alpha darken' blend methods. Why were they hidde...
[synfig.git] / synfig-core / trunk / src / synfig / canvas.cpp
index 59d54af..74c737f 100644 (file)
@@ -1016,7 +1016,7 @@ Canvas::get_meta_data_keys()const
                  refer to "motion blur", they mean either of these two
                  layers. */
 void
-synfig::optimize_layers(Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
+synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
 {
        Context iter;
 
@@ -1082,12 +1082,12 @@ synfig::optimize_layers(Context context, Canvas::Handle op_canvas, bool seen_mot
                if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
                        continue;
 
-               Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
-
                // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
                //               time-shifted layers weren't being sorted by z-depth (bug #1806852)
                if(layer->get_name()=="PasteCanvas")
                {
+                       Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
+
                        // we need to blur the sub canvas if:
                        // our parent is blurred,
                        // or the child is lower than a local blur,
@@ -1112,9 +1112,10 @@ synfig::optimize_layers(Context context, Canvas::Handle op_canvas, bool seen_mot
                        Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
                        Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
                        if(paste_sub_canvas)
-                               optimize_layers(paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
-//#define SYNFIG_OPTIMIZE_PASTE_CANVAS 1
+                               optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
 
+// \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
+// #define SYNFIG_OPTIMIZE_PASTE_CANVAS
 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
                        Canvas::iterator sub_iter;
 
@@ -1169,6 +1170,44 @@ synfig::optimize_layers(Context context, Canvas::Handle op_canvas, bool seen_mot
                        dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
                        layer=new_layer;
                }
+               else                                    // not a PasteCanvas - does it use blend method 'Straight'?
+               {
+                       /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
+                        * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
+                        * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
+                        * within the layer's bounding box
+                        */
+
+                       // \todo: this code probably needs modification to work properly with motionblur and duplicate
+                       etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
+
+                       /* some layers (such as circle) don't touch pixels that aren't
+                        * part of the circle, so they don't get blended correctly when
+                        * using a straight blend.  so we encapsulate the circle, and the
+                        * encapsulation layer takes care of the transparent pixels
+                        * for us.  if we do that for all layers, however, then the
+                        * distortion layers no longer work, since they have no
+                        * context to work on.  the Layer::reads_context() method
+                        * returns true for layers which need to be able to see
+                        * their context.  we can't encapsulate those.
+                        */
+                       if (composite &&
+                               Color::is_straight(composite->get_blend_method()) &&
+                               !composite->reads_context())
+                       {
+                               Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
+                               sub_canvas->push_back(composite = composite->clone());
+                               layer = Layer::create("PasteCanvas");
+                               layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
+                               Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
+                               paste_canvas->set_blend_method(composite->get_blend_method());
+                               paste_canvas->set_amount(composite->get_amount());
+                               composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_time() or set_sub_canvas()
+                               composite->set_amount(1.0f);
+                               sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
+                               paste_canvas->set_sub_canvas(sub_canvas);
+                       }
+               }
 
                sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
                //op_canvas->push_back_simple(layer);