Added copyright lines for files I've edited this year.
[synfig.git] / synfig-core / trunk / src / modules / mod_geometry / rectangle.cpp
index 1e81239..21fa4d2 100644 (file)
@@ -1,11 +1,12 @@
 /* === S Y N F I G ========================================================= */
 /*!    \file rectangle.cpp
-**     \point2ief Template Header
+**     \brief Implementation of the "Rectangle" layer
 **
-**     $Id: rectangle.cpp,v 1.2 2005/01/24 03:08:17 darco Exp $
+**     $Id$
 **
 **     \legal
 **     Copyright (c) 2002 Robert B. Quattlebaum Jr.
+**     Copyright (c) 2007, 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
@@ -54,10 +55,10 @@ using namespace synfig;
 
 SYNFIG_LAYER_INIT(Rectangle);
 SYNFIG_LAYER_SET_NAME(Rectangle,"rectangle");
-SYNFIG_LAYER_SET_LOCAL_NAME(Rectangle,_("Rectangle"));
-SYNFIG_LAYER_SET_CATEGORY(Rectangle,_("Geometry"));
+SYNFIG_LAYER_SET_LOCAL_NAME(Rectangle,N_("Rectangle"));
+SYNFIG_LAYER_SET_CATEGORY(Rectangle,N_("Geometry"));
 SYNFIG_LAYER_SET_VERSION(Rectangle,"0.2");
-SYNFIG_LAYER_SET_CVS_ID(Rectangle,"$Id: rectangle.cpp,v 1.2 2005/01/24 03:08:17 darco Exp $");
+SYNFIG_LAYER_SET_CVS_ID(Rectangle,"$Id$");
 
 /* === P R O C E D U R E S ================================================= */
 
@@ -82,16 +83,18 @@ Rectangle::Rectangle():
        invert(false)
 {
 }
-       
+
 bool
 Rectangle::set_param(const String & param, const ValueBase &value)
 {
-       IMPORT(color);
+       IMPORT_PLUS(color, { if (color.get_a() == 0) { if (converted_blend_) {
+                                       set_blend_method(Color::BLEND_ALPHA_OVER);
+                                       color.set_a(1); } else transparent_color_ = true; } });
        IMPORT(point1);
        IMPORT(point2);
        IMPORT(expand);
        IMPORT(invert);
-       
+
        return Layer_Composite::set_param(param,value);
 }
 
@@ -106,15 +109,15 @@ Rectangle::get_param(const String &param)const
 
        EXPORT_NAME();
        EXPORT_VERSION();
-               
-       return Layer_Composite::get_param(param);       
+
+       return Layer_Composite::get_param(param);
 }
 
 Layer::Vocab
 Rectangle::get_param_vocab()const
 {
        Layer::Vocab ret(Layer_Composite::get_param_vocab());
-       
+
        ret.push_back(ParamDesc("color")
                .set_local_name(_("Color"))
        );
@@ -123,7 +126,7 @@ Rectangle::get_param_vocab()const
                .set_local_name(_("Point 1"))
                .set_box("point2")
        );
-       
+
        ret.push_back(ParamDesc("point2")
                .set_local_name(_("Point 2"))
        );
@@ -132,7 +135,7 @@ Rectangle::get_param_vocab()const
                .set_is_distance()
                .set_local_name(_("Expand amount"))
        );
-       
+
        ret.push_back(ParamDesc("invert")
                .set_local_name(_("Invert the rectangle"))
        );
@@ -154,7 +157,7 @@ Rectangle::hit_check(synfig::Context context, const synfig::Point &pos)const
        min[1]=std::min(point1[1],point2[1])-expand;
 
        bool intersect(false);
-       
+
        if(     pos[0]<max[0] && pos[0]>min[0] &&
                pos[1]<max[1] && pos[1]>min[1] )
        {
@@ -163,7 +166,7 @@ Rectangle::hit_check(synfig::Context context, const synfig::Point &pos)const
 
        if(invert)
                intersect=!intersect;
-       
+
        if(intersect)
        {
                synfig::Layer::Handle tmp;
@@ -177,6 +180,15 @@ Rectangle::hit_check(synfig::Context context, const synfig::Point &pos)const
        return context.hit_check(pos);
 }
 
+bool
+Rectangle::is_solid_color()const
+{
+       return Layer_Composite::is_solid_color() ||
+               (get_blend_method() == Color::BLEND_COMPOSITE &&
+                get_amount() == 1.0f &&
+                color.get_a() == 1.0f);
+}
+
 Color
 Rectangle::get_color(Context context, const Point &pos)const
 {
@@ -189,10 +201,10 @@ Rectangle::get_color(Context context, const Point &pos)const
        max[1]=std::max(point1[1],point2[1])+expand;
        min[0]=std::min(point1[0],point2[0])-expand;
        min[1]=std::min(point1[1],point2[1])-expand;
-       
+
 /**************************
 // This is darco's old-old-old feathered box code
-// it produces really nice feathered edges     
+// it produces really nice feathered edges
        if(feather!=0.0)
        {
                if(     pos[0]<=max[0]-feather/2.0 && pos[0]>=min[0]+feather/2.0 &&
@@ -215,12 +227,12 @@ Rectangle::get_color(Context context, const Point &pos)const
 
                Color::unit alpha=1000000;
                Color::unit alpha2=1000000;
-               
+
                if(max[0]-pos[0]+feather/2.0<alpha)
                        alpha=max[0]-pos[0]+feather/2.0;
                if(pos[0]-min[0]+feather/2.0<alpha)
                        alpha=pos[0]-min[0]+feather/2.0;
-               
+
                if(max[1]-pos[1]+feather/2.0<alpha2)
                        alpha2=max[1]-pos[1]+feather/2.0;
                if(pos[1]-min[1]+feather/2.0<alpha2)
@@ -233,7 +245,7 @@ Rectangle::get_color(Context context, const Point &pos)const
                        alpha2=feather-alpha2;
 
                        alpha=sqrt(alpha*alpha+alpha2*alpha2);
-                       
+
                        if(alpha>=feather)
                        {
                                if(invert)
@@ -256,7 +268,7 @@ Rectangle::get_color(Context context, const Point &pos)const
 
                return Color::blend(color,context.get_color(pos),alpha,get_blend_method());
        }
-       
+
 *****************/
 
        if(     pos[0]<max[0] && pos[0]>min[0] &&
@@ -270,7 +282,7 @@ Rectangle::get_color(Context context, const Point &pos)const
                                return color;
                        else
                                return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method());
-                               
+
                }
        }
 
@@ -287,7 +299,7 @@ Rectangle::get_color(Context context, const Point &pos)const
 
 bool
 Rectangle::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
-{      
+{
        if(is_disabled())
                return context.accelerated_render(surface,quality,renddesc,cb);
 
@@ -302,12 +314,12 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
        const Real ph = (br[1] - tl[1]) / h;
 
        Point max(point1),min(point2);
-       
-       
-       
-       
+
+
+
+
        /*
-       
+
        if(invert)
        {
                max=context.get_bounding_rect().get_max();
@@ -319,14 +331,14 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
                min=context.get_full_bounding_rect().get_min();
        }
        */
-       
-       
-       
-       
-       
+
+
+
+
+
        if((min[0] > max[0]) ^ (pw < 0))swap(min[0],max[0]);
        if((min[1] > max[1]) ^ (ph < 0))swap(min[1],max[1]);
-       
+
        if(min[0] > max[0])
        {
                min[0]+=expand;
@@ -348,49 +360,49 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
                min[1]-=expand;
                max[1]+=expand;
        }
-               
+
        if(invert)
        {
                int left(floor_to_int((min[0]-tl[0])/pw));
                int right(ceil_to_int((max[0]-tl[0])/pw));
                int top(floor_to_int((min[1]-tl[1])/ph));
                int bottom(ceil_to_int((max[1]-tl[1])/ph));
-       
+
                float left_edge((min[0]-tl[0])/pw-float(left));
                float right_edge(float(right)-(max[0]-tl[0])/pw);
                float top_edge((min[1]-tl[1])/ph-float(top));
                float bottom_edge(float(bottom)-(max[1]-tl[1])/ph);
-                       
+
                if(top<0)top=0,top_edge=0;
                if(left<0)left=0,left_edge=0;
                if(bottom>h)bottom=h,bottom_edge=0;
                if(right>w)right=w,right_edge=0;
-                       
+
                if(is_solid_color())
                {
                        Surface subimage;
                        RendDesc desc(renddesc);
                        desc.set_flags(0);
-                                       
+
                        //fill the surface with the background color initially
                        surface->set_wh(w,h);
                        surface->fill(color);
-       
+
                        // Check for the case where there is nothing to render
-                       if(right-left<=0||bottom-top<=0)
+                       if (right <= left || bottom <= top)
                                return true;
-                       
+
                        desc.set_subwindow(left,top,right-left,bottom-top);
-       
+
                        // Render what is behind us
                        if(!context.accelerated_render(&subimage,quality,desc,cb))
                        {
                                if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
                                return false;
                        }
-                       
+
                        Surface::pen pen(surface->get_pen(left,top));
-                       
+
                        subimage.blit_to(pen);
                }
                else
@@ -400,25 +412,31 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
                                if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
                                return false;
                        }
+
                        Surface subimage;
 
-                       // Check for the case where there is nothing to render
-                       if(!(right-left<=0||bottom-top<=0))
+                       // Check for the case where there is something to render
+                       if (right > left && bottom > top)
                        {
+                               // save a copy of the overlapping region from surface into subimage
                                subimage.set_wh(right-left,bottom-top);
                                Surface::pen subimage_pen(subimage.begin());
                                surface->blit_to(subimage_pen,left,top,right-left,bottom-top);
                        }
 
+                       // fill surface with the rectangle's color
                        Surface::alpha_pen surface_pen(surface->begin(),get_amount(),get_blend_method());
-               
                        surface->fill(color,surface_pen,w,h);
 
-                       if(subimage)
+                       if (subimage)
                        {
+                               // copy the saved overlapping region back from subimage into surface
                                Surface::pen pen(surface->get_pen(left,top));
                                subimage.blit_to(pen);
                        }
+                       else
+                               // if there's no overlapping region, return now of the following code corrupts memory
+                               return true;
                }
 
                Surface::alpha_pen pen;
@@ -428,34 +446,29 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
                        pen=Surface::alpha_pen(surface->get_pen(left,bottom-1),get_amount()*bottom_edge,get_blend_method());
                        surface->fill(color,pen,right-left,1);
                }
-               
+
                if(right-1>=0 && right_edge)
                {
                        pen=Surface::alpha_pen(surface->get_pen(right-1,top),get_amount()*right_edge,get_blend_method());
                        surface->fill(color,pen,1,bottom-top);
                }
-               
+
                if(left>=0 && left_edge)
                {
                        pen=Surface::alpha_pen(surface->get_pen(left,top),get_amount()*left_edge,get_blend_method());
                        surface->fill(color,pen,1,bottom-top);
                }
-               
+
                if(top>=0 && top_edge)
                {
                        pen=Surface::alpha_pen(surface->get_pen(left,top),get_amount()*top_edge,get_blend_method());
                        surface->fill(color,pen,right-left,1);
                }
-               
+
                return true;
        }
 
-       // Render what is behind us
-       if(!context.accelerated_render(surface,quality,renddesc,cb))
-       {
-               if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
-               return false;
-       }
+       // not inverted
 
        int left(ceil_to_int((min[0]-tl[0])/pw));
        int right(floor_to_int((max[0]-tl[0])/pw));
@@ -466,7 +479,7 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
        float right_edge((max[0]-tl[0])/pw-float(right));
        float top_edge(float(top)-(min[1]-tl[1])/ph);
        float bottom_edge((max[1]-tl[1])/ph-float(bottom));
-               
+
        if(top<=0)top=0,top_edge=0;
        if(left<=0)left=0,left_edge=0;
        if(bottom>=h)bottom=h,bottom_edge=0;
@@ -478,24 +491,41 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
        bottom = std::min(h,bottom);
        right = std::min(w,right);
 */
-       
-       Surface::alpha_pen pen;
+
+       // optimization - if the whole tile is covered by this rectangle,
+       // and the rectangle is a solid color, we don't need to render
+       // what's behind us
+       if (is_solid_color() && top == 0 && left == 0 && bottom == h && right == w)
+       {
+               surface->set_wh(w,h);
+               surface->fill(color);
+               return true;
+       }
+
+       // Render what is behind us
+       if(!context.accelerated_render(surface,quality,renddesc,cb))
+       {
+               if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
+               return false;
+       }
 
        // In the case where there is nothing to render...
-       if(right-left<0||bottom-top<0)
+       if (right < left || bottom < top)
                return true;
-       
+
+       Surface::alpha_pen pen;
+
        if(right-left>0&&bottom-top>0)
        {
                if(is_solid_color())
                        surface->fill(color,left,top,right-left,bottom-top);
                else
-               {       
+               {
                        pen=Surface::alpha_pen(surface->get_pen(left,top),get_amount(),get_blend_method());
                        surface->fill(color,pen,right-left,bottom-top);
                }
        }
-       
+
        if(bottom<surface->get_h() && bottom_edge>=0.0001)
        {
                pen=Surface::alpha_pen(surface->get_pen(left,bottom),get_amount()*bottom_edge,get_blend_method());
@@ -507,7 +537,7 @@ Rectangle::accelerated_render(Context context,Surface *surface,int quality, cons
                pen=Surface::alpha_pen(surface->get_pen(right,top),get_amount()*right_edge,get_blend_method());
                surface->fill(color,pen,1,bottom-top);
        }
-       
+
        if(left>0 && left_edge>=0.0001)
        {
                pen=Surface::alpha_pen(surface->get_pen(left-1,top),get_amount()*left_edge,get_blend_method());
@@ -530,9 +560,9 @@ Rectangle::get_bounding_rect()const
        if(invert)
                return Rect::full_plane();
 
-       Point max(point1),min(point2);  
+       Point max(point1),min(point2);
        if((min[0] > max[0]))swap(min[0],max[0]);
-       if((min[1] > max[1]))swap(min[1],max[1]);       
+       if((min[1] > max[1]))swap(min[1],max[1]);
        if(min[0] > max[0])
        {
                min[0]+=expand;
@@ -567,9 +597,9 @@ Rectangle::get_full_bounding_rect(Context context)const
        {
                if(is_solid_color() && color.get_a()==0)
                {
-                       Point max(point1),min(point2);  
+                       Point max(point1),min(point2);
                        if((min[0] > max[0]))swap(min[0],max[0]);
-                       if((min[1] > max[1]))swap(min[1],max[1]);       
+                       if((min[1] > max[1]))swap(min[1],max[1]);
                        if(min[0] > max[0])
                        {
                                min[0]+=expand;
@@ -596,7 +626,7 @@ Rectangle::get_full_bounding_rect(Context context)const
 
                        return bounds & context.get_full_bounding_rect();
                }
-               return Rect::full_plane();                      
+               return Rect::full_plane();
        }
 
        return Layer_Composite::get_full_bounding_rect(context);