Author: Carlos Lopez <[email protected]>
Date:   Sat Jul 21 11:19:44 2012 +0200

Rectangle: initial version of accelerated_cairorender. It works fine for non 
inverted rectangles but doesn't work properly for inverted rectangles yet. 
Blending modes not fully supported.

---

 synfig-core/src/modules/mod_geometry/rectangle.cpp |  189 ++++++++++++++++++++
 synfig-core/src/modules/mod_geometry/rectangle.h   |    1 +
 2 files changed, 190 insertions(+), 0 deletions(-)

diff --git a/synfig-core/src/modules/mod_geometry/rectangle.cpp 
b/synfig-core/src/modules/mod_geometry/rectangle.cpp
index 9ec1f01..e953acd 100644
--- a/synfig-core/src/modules/mod_geometry/rectangle.cpp
+++ b/synfig-core/src/modules/mod_geometry/rectangle.cpp
@@ -559,6 +559,195 @@ Rectangle::accelerated_render(Context context,Surface 
*surface,int quality, cons
        return true;
 }
 
+//////
+
+bool
+Rectangle::accelerated_cairorender(Context context,cairo_surface_t 
*surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
+{
+       if(is_disabled())
+               return 
context.accelerated_cairorender(surface,quality,renddesc,cb);
+       
+       Color dcolor(color/*.premult_alpha()*/);
+       const float r(dcolor.get_r());
+       const float g(dcolor.get_g());
+       const float b(dcolor.get_b());
+       const float a(dcolor.get_a());
+       
+       const Point     tl(renddesc.get_tl());
+       const Point br(renddesc.get_br());
+       
+       const int       w(renddesc.get_w());
+       const int       h(renddesc.get_h());
+
+       // Width and Height of a pixel
+       const Real pw = (br[0] - tl[0]) / w;
+       const Real ph = (br[1] - tl[1]) / h;
+       Point min(point1), max(point2);
+
+       // if x max, min are swaped then swap the x coordinate
+       if(min[0] > max[0]) swap(min[0],max[0]);
+       // if y max min are swaped then swap the y coordinate
+       if(min[1] > max[1]) swap(min[1],max[1]);
+       // min is the lower left corner and max is the upper right corner 
+       // now we need to expand the edges
+       min[0]-=expand;
+       max[0]+=expand;
+       min[1]-=expand;
+       max[1]+=expand;
+       //
+       //synfig::info("min=%f, %f     max=%f, %f", min[0], min[1], max[0], 
max[1]);
+       //
+       cairo_t* cr=cairo_create(surface);
+       // This is a rectangle with the same dimensions of the rectangle
+       const Rect shape(min, max);
+       // This is a rectangle with the same dimensions of the canvas
+       const Rect dest(tl, br);
+       Rect inter(dest);
+       // inter holds the intersection rectangle of both rectangles.
+       inter&=shape;   
+
+       Point inter_min(inter.get_min());
+       Point inter_max(inter.get_max());
+       //
+       //synfig::info("intermin=%f, %f     intermax=%f, %f", inter_min[0], 
inter_min[1], inter_max[0], inter_max[1]);
+       //
+       if(invert)
+       {
+               if(is_solid_color())
+               {
+                       // The rectangle is inverted and is solid color
+                       // Let's do this:
+                       // Fill the surface with the color intially
+                       cairo_save(cr);
+                       cairo_set_source_rgba(cr, r, g, b, a); // a=1.0
+                       cairo_paint(cr);
+                       cairo_restore(cr);
+                       
+                       // Check for the case where there is nothing to render
+                       if (inter.area()<0.00000001)
+                       {
+                               cairo_destroy(cr);
+                               return true;
+                       }
+                       // Modify the Render Description to render on the 
intersection.
+                       // this will modify the w and h values in pixels.
+                       RendDesc desc(renddesc);
+                       //desc.set_flags(0);
+                       desc.set_tl(Point(inter.get_min()[0], 
inter.get_max()[1]));
+                       desc.set_br(Point(inter.get_max()[0], 
inter.get_min()[1]));
+                       // create a new similar surface with the wxh dimensions
+                       cairo_surface_t* 
subimage=cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, 
desc.get_w(), desc.get_h());
+                       synfig::info("w=%d, h=%d", desc.get_w(), desc.get_h());
+                       synfig::info("tl=%f,%f br=%f,%f", desc.get_tl()[0], 
desc.get_tl()[1], desc.get_br()[0], desc.get_br()[1] );
+                       // Render what is behind us
+                       
if(!context.accelerated_cairorender(subimage,quality,desc,cb))
+                       {
+                               if(cb)cb->error(strprintf(__FILE__"%d: 
Accelerated Cairo Renderer Failure",__LINE__));
+                               {
+                                       cairo_surface_destroy(subimage);
+                                       cairo_destroy(cr);
+                                       return false;
+                               }
+                       }
+                       cairo_save(cr);
+                       double width (inter_max[0]-inter_min[0]);
+                       double height(inter_max[1]-inter_min[1]);
+                       double tx((br[0]-tl[0])/2/pw);
+                       double ty((br[1]-tl[1])/2/ph);
+                       double sx(1/pw);
+                       double sy(1/ph);  
+                       cairo_translate(cr, tx , ty);
+                       cairo_scale(cr, sx, sy);
+                       cairo_rectangle(cr, inter_min[0], inter_min[1], width, 
height);
+                       cairo_clip(cr);
+                       cairo_set_source_surface(cr, subimage, 0, 0 
/*inter_min[0], inter_min[1]*/);
+                       cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+                       cairo_paint(cr);
+                       cairo_restore(cr);
+                       cairo_surface_destroy(subimage);
+                       cairo_destroy(cr);
+                       return true;
+               }
+               else // not solid color so we need to render what's behind
+               {
+                       // Initially render what's behind us
+                       
if(!context.accelerated_cairorender(surface,quality,renddesc,cb))
+                       {
+                               if(cb)cb->error(strprintf(__FILE__"%d: 
Accelerated Cairo Renderer Failure",__LINE__));
+                               cairo_destroy(cr);
+                               return false;
+                       }
+                       // Now let's render the rectangle in other surface
+                       // Initially I'll fill it completely with the alpha 
color 
+                       // Create a similar image with the same dimensions than 
the current renddesc
+                       cairo_surface_t* 
subimage=cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, 
renddesc.get_w(), renddesc.get_h());
+                       cairo_t* subcr=cairo_create(subimage);
+                       cairo_set_source_rgba(subcr, r, g, b, a);
+                       cairo_paint(subcr);
+                       // now remove the area of the intersection rectangle
+                       cairo_rectangle(subcr, inter_min[0], inter_min[1], 
inter_max[0]-inter_min[0], inter_max[1]-inter_min[1]);
+                       cairo_set_operator(subcr, CAIRO_OPERATOR_CLEAR);
+                       cairo_fill(cr);
+                       // now let's paint the inverted rectangle with the hole 
on the rendered context 
+                       cairo_save(cr);
+                       cairo_set_source_surface(cr, subimage, 0, 0);
+                       cairo_set_operator(cr, CAIRO_OPERATOR_OVER); // TODO 
this has to be the real operator
+                       cairo_paint_with_alpha(cr, get_amount());
+                       cairo_restore(cr);
+                       cairo_surface_destroy(subimage);
+                       cairo_destroy(subcr);
+                       cairo_destroy(cr);
+                       return true;                    
+               }
+       }
+       
+       // not inverted
+       // optimization - if the whole canvas 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() && inter==Rect(tl, br))
+       {
+               cairo_set_source_rgba(cr, r, g, b, a);
+               cairo_paint(cr);
+               cairo_destroy(cr);
+               return true;
+       }
+       // The rectangle intersects the canvas partially
+       // Render what is behind us
+       if(!context.accelerated_cairorender(surface,quality,renddesc,cb))
+       {
+               if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Cairo 
Renderer Failure",__LINE__));
+               cairo_destroy(cr);
+               return false;
+       }
+       
+       // In the case where there is nothing to render...
+       if (inter.area()<0.00000001)
+               return true;
+       
+       cairo_set_source_rgba(cr, r, g, b, a);
+       double width (inter_max[0]-inter_min[0]);
+       double height(inter_max[1]-inter_min[1]);
+       double tx((br[0]-tl[0])/2/pw);
+       double ty((br[1]-tl[1])/2/ph);
+       double sx(1/pw);
+       double sy(1/ph);  
+       cairo_translate(cr, tx , ty);
+       cairo_scale(cr, sx, sy);
+       cairo_rectangle(cr, inter_min[0], inter_min[1], width, height);
+       cairo_clip(cr);
+       if(is_solid_color())
+               cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 
+       else
+               cairo_set_operator(cr, CAIRO_OPERATOR_OVER); // TODO this has 
to be the real operator
+       cairo_paint_with_alpha(cr, get_amount());
+       cairo_destroy(cr);      
+       return true;
+}
+
+
+//////
+
 Rect
 Rectangle::get_bounding_rect()const
 {
diff --git a/synfig-core/src/modules/mod_geometry/rectangle.h 
b/synfig-core/src/modules/mod_geometry/rectangle.h
index add217c..ab7a4a4 100644
--- a/synfig-core/src/modules/mod_geometry/rectangle.h
+++ b/synfig-core/src/modules/mod_geometry/rectangle.h
@@ -67,6 +67,7 @@ public:
        virtual synfig::Color get_color(synfig::Context context, const 
synfig::Point &pos)const;
 
        virtual bool accelerated_render(synfig::Context context,synfig::Surface 
*surface,int quality, const synfig::RendDesc &renddesc, 
synfig::ProgressCallback *cb)const;
+       virtual bool accelerated_cairorender(synfig::Context context, 
cairo_surface_t *surface,int quality, const synfig::RendDesc &renddesc, 
synfig::ProgressCallback *cb)const;
 
        synfig::Layer::Handle hit_check(synfig::Context context, const 
synfig::Point &point)const;
 


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Synfig-devl mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/synfig-devl

Reply via email to