Author: Carlos Lopez <[email protected]>
Date:   Fri Sep 28 20:00:32 2012 +0200

Shade layer: Add support for Cairo render

---

 synfig-core/src/modules/lyr_std/shade.cpp |  183 +++++++++++++++++++++++++++++
 synfig-core/src/modules/lyr_std/shade.h   |    1 +
 2 files changed, 184 insertions(+), 0 deletions(-)

diff --git a/synfig-core/src/modules/lyr_std/shade.cpp 
b/synfig-core/src/modules/lyr_std/shade.cpp
index d0f0686..b0529f2 100644
--- a/synfig-core/src/modules/lyr_std/shade.cpp
+++ b/synfig-core/src/modules/lyr_std/shade.cpp
@@ -368,6 +368,189 @@ Layer_Shade::accelerated_render(Context context,Surface 
*surface,int quality, co
        return true;
 }
 
+
+///
+bool
+Layer_Shade::accelerated_cairorender(Context context,cairo_surface_t 
*surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
+{
+       int x,y;
+
+       const int       w = renddesc.get_w(),
+       h = renddesc.get_h();
+       const Real      pw = renddesc.get_pw(),
+       ph = renddesc.get_ph();
+       
+       RendDesc        workdesc(renddesc);
+       cairo_surface_t         *worksurface;
+       etl::surface<float> blurred;
+       
+       //expand the working surface to accommodate the blur    
+       //the expanded size = 1/2 the size in each direction rounded up
+       int     halfsizex = (int) (abs(size[0]*.5/pw) + 3),
+       halfsizey = (int) (abs(size[1]*.5/ph) + 3);
+       
+       int 
origin_u(-round_to_int(origin[0]/pw)),origin_v(-round_to_int(origin[1]/ph));
+       
+       int origin_w(w+abs(origin_u)),origin_h(h+abs(origin_v));
+       
+       workdesc.set_subwindow(
+                                                  origin_u<0?origin_u:0,
+                                                  origin_v<0?origin_v:0,
+                                                  (origin_u>0?origin_u:0)+w,
+                                                  (origin_v>0?origin_v:0)+h
+                                                  );
+       
+       if(quality >= 10)
+       {
+               halfsizex=1;
+               halfsizey=1;
+       }
+       else if (quality == 9)
+       {
+               halfsizex/=4;
+               halfsizey/=4;
+       }
+#define SCALE_FACTOR   (64.0)
+       //expand by 1/2 size in each direction on either side
+       switch(type)
+       {
+               case Blur::DISC:
+               case Blur::BOX:
+               case Blur::CROSS:
+               {
+                       // If passed a certain size don't expand more
+                       halfsizex=halfsizex>SCALE_FACTOR?SCALE_FACTOR:halfsizex;
+                       halfsizey=halfsizey>SCALE_FACTOR?SCALE_FACTOR:halfsizey;
+                       
workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),origin_w+2*max(1,halfsizex),origin_h+2*max(1,halfsizey));
+                       break;
+               }
+               case Blur::FASTGAUSSIAN:
+               {
+                       if(quality < 4)
+                       {
+                               halfsizex*=2;
+                               halfsizey*=2;
+                       }
+                       // If passed a certain size don't expand more
+                       halfsizex=halfsizex>SCALE_FACTOR?SCALE_FACTOR:halfsizex;
+                       halfsizey=halfsizey>SCALE_FACTOR?SCALE_FACTOR:halfsizey;
+                       
workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),origin_w+2*max(1,halfsizex),origin_h+2*max(1,halfsizey));
+                       break;
+               }
+               case Blur::GAUSSIAN:
+               {
+#define GAUSSIAN_ADJUSTMENT            (0.05)
+                       Real    pw = 
(Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
+                       Real    ph = 
(Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
+                       
+                       pw=pw*pw;
+                       ph=ph*ph;
+                       
+                       halfsizex = 
(int)(abs(pw)*size[0]*GAUSSIAN_ADJUSTMENT+0.5);
+                       halfsizey = 
(int)(abs(ph)*size[1]*GAUSSIAN_ADJUSTMENT+0.5);
+                       
+                       halfsizex = (halfsizex + 1)/2;
+                       halfsizey = (halfsizey + 1)/2;
+                       // If passed a certain size don't expand more
+                       halfsizex=halfsizex>SCALE_FACTOR?SCALE_FACTOR:halfsizex;
+                       halfsizey=halfsizey>SCALE_FACTOR?SCALE_FACTOR:halfsizey;
+                       workdesc.set_subwindow( -halfsizex, -halfsizey, 
origin_w+2*halfsizex, origin_h+2*halfsizey );
+                       
+                       break;
+               }
+       }
+       SuperCallback stageone(cb,0,5000,10000);
+       SuperCallback stagetwo(cb,5000,10000,10000);
+       
+       //callbacks depend on how long the blur takes
+       if(size[0] || size[1])
+       {
+               if(type == Blur::DISC)
+               {
+                       stageone = SuperCallback(cb,0,5000,10000);
+                       stagetwo = SuperCallback(cb,5000,10000,10000);
+               }
+               else
+               {
+                       stageone = SuperCallback(cb,0,9000,10000);
+                       stagetwo = SuperCallback(cb,9000,10000,10000);
+               }
+       }
+       else
+       {
+               stageone = SuperCallback(cb,0,9999,10000);
+               stagetwo = SuperCallback(cb,9999,10000,10000);
+       }
+       
+       
+       // setup the worksurface
+       worksurface=cairo_surface_create_similar(surface, 
CAIRO_CONTENT_COLOR_ALPHA, workdesc.get_w(), workdesc.get_h());
+
+       //render the background onto the expanded surface
+       
if(!context.accelerated_cairorender(worksurface,quality,workdesc,&stageone))
+               return false;
+       // copy the background on the target surface if applies
+       if(!is_solid_color())
+       {
+               cairo_t *cr=cairo_create(surface);
+               cairo_set_source_surface(cr, worksurface, 
-halfsizex+(origin_u<0?origin_u:0), -halfsizey+(origin_v<0?origin_v:0));
+               cairo_paint(cr);
+               cairo_destroy(cr);
+       }
+       
+       // Extract the CairoSurface from the cairo_surface_t
+       CairoSurface cairoworksurface(worksurface);
+       if(!cairoworksurface.map_cairo_image())
+       {
+               synfig::info("map cairo image failed");
+               return false;
+       }
+       // Extract the alpha
+       blurred.set_wh(workdesc.get_w(),workdesc.get_h());
+       for(int j=0;j<workdesc.get_h();j++)
+               for(int i=0;i<workdesc.get_w();i++)
+                       
blurred[j][i]=cairoworksurface[j][i].get_a()/CairoColor::ceil;
+       
+       //blur the image
+       
Blur(size,type,&stagetwo)(blurred,workdesc.get_br()-workdesc.get_tl(),blurred);
+       
+       // repaint the cairosubimage with the result. Use the layer's amount 
here (is faster)
+       Color ccolor(color);
+       float am=get_amount();
+       for(y=0; y<workdesc.get_h(); y++)
+               for(x=0;x<workdesc.get_w();x++)
+               {
+                       float a=blurred[y][x];
+                       ccolor.set_a(a*am);
+                       ccolor.clamped();
+                       
cairoworksurface[y][x]=CairoColor(ccolor).premult_alpha();
+               }
+       
+       cairoworksurface.unmap_cairo_image();
+
+       // Now lets blend the result in the output surface
+       cairo_t *cr=cairo_create(surface);
+       cairo_set_source_surface(cr, worksurface, 
-halfsizex+(origin_u<0?origin_u:0)-origin_u, 
-halfsizey+(origin_v<0?origin_v:0)-origin_v);
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER); // TODO this has to be the 
real operator
+       cairo_paint(cr); // not need to paint with alpha because it is already 
included
+       cairo_destroy(cr);
+       
+       cairo_surface_destroy(worksurface);
+               
+#undef GAUSSIAN_ADJUSTMENT
+#undef SCALE_FACTOR
+
+       if(cb && !cb->amount_complete(10000,10000))
+       {
+               //if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer 
Failure",__LINE__));
+               return false;
+       }
+       
+       return true;
+}
+
+///
+
 Layer::Vocab
 Layer_Shade::get_param_vocab(void)const
 {
diff --git a/synfig-core/src/modules/lyr_std/shade.h 
b/synfig-core/src/modules/lyr_std/shade.h
index ec16ad1..13867b0 100644
--- a/synfig-core/src/modules/lyr_std/shade.h
+++ b/synfig-core/src/modules/lyr_std/shade.h
@@ -57,6 +57,7 @@ public:
        virtual Color get_color(Context context, const Point &pos)const;
 
        virtual bool accelerated_render(Context context,Surface *surface,int 
quality, const RendDesc &renddesc, ProgressCallback *cb)const;
+       virtual bool accelerated_cairorender(Context context,cairo_surface_t 
*surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
        virtual Rect get_full_bounding_rect(Context context)const;
        virtual Vocab get_param_vocab()const;
        virtual bool reads_context()const { return true; }


------------------------------------------------------------------------------
Got visibility?
Most devs has no idea what their production app looks like.
Find out how fast your code is with AppDynamics Lite.
http://ad.doubleclick.net/clk;262219671;13503038;y?
http://info.appdynamics.com/FreeJavaPerformanceDownload.html
_______________________________________________
Synfig-devl mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/synfig-devl

Reply via email to