Author: Carlos Lopez <genet...@gmail.com> Date: Tue Aug 14 10:08:28 2012 +0200
Region: add support for Cairo render. --- synfig-core/src/modules/mod_geometry/region.cpp | 215 +++++++++++++++++++++++ synfig-core/src/modules/mod_geometry/region.h | 2 +- 2 files changed, 216 insertions(+), 1 deletions(-) diff --git a/synfig-core/src/modules/mod_geometry/region.cpp b/synfig-core/src/modules/mod_geometry/region.cpp index e765373..c536325 100644 --- a/synfig-core/src/modules/mod_geometry/region.cpp +++ b/synfig-core/src/modules/mod_geometry/region.cpp @@ -251,3 +251,218 @@ Region::set_time(Context context, Time time, Vector pos)const const_cast<Region*>(this)->sync(); context.set_time(time,pos); } + +///////// +bool +Region::accelerated_cairorender(Context context,cairo_surface_t *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + synfig::info("rendering Cairo Region"); + std::vector<synfig::Segment> segments; + + // Grab the rgba values + const float r(color.get_r()); + const float g(color.get_g()); + const float b(color.get_b()); + const float a(color.get_a()); + + // Window Boundaries + 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; + + // These are the scale and translation values + const double sx(1/pw); + const double sy(1/ph); + const double tx((-tl[0]+origin[0])*sx); + const double ty((-tl[1]+origin[1])*sy); + + if(bline.get_contained_type()==ValueBase::TYPE_BLINEPOINT) + segments=convert_bline_to_segment_list(bline); + else if(bline.get_contained_type()==ValueBase::TYPE_SEGMENT) + segments=vector<synfig::Segment>(bline.get_list().begin(), bline.get_list().end()); + else + { + synfig::warning("Region: incorrect type on bline, layer disabled"); + return false; + } + + if(segments.empty()) + { + synfig::warning("Region: segment_list is empty, layer disabled"); + return false; + } + + cairo_t* cr=cairo_create(surface); + // Let's render the region in other surface + // Initially I'll fill it completely with the alpha color + cairo_surface_t* subimage; + // Let's calculate the subimage dimensions based on the feather value + //so make a separate surface + RendDesc workdesc(renddesc); + int halfsizex(0), halfsizey(0); + if(feather && quality != 10) + { + //the expanded size = 1/2 the size in each direction rounded up + halfsizex = (int) (abs(feather*.5/pw) + 3), + halfsizey = (int) (abs(feather*.5/ph) + 3); + + //expand by 1/2 size in each direction on either side + switch(blurtype) + { + case Blur::DISC: + case Blur::BOX: + case Blur::CROSS: + { + workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); + break; + } + case Blur::FASTGAUSSIAN: + { + if(quality < 4) + { + halfsizex*=2; + halfsizey*=2; + } + workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),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)*feather*GAUSSIAN_ADJUSTMENT+0.5); + halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5); + + halfsizex = (halfsizex + 1)/2; + halfsizey = (halfsizey + 1)/2; + workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey ); + break; +#undef GAUSSIAN_ADJUSTMENT + } + } + } + subimage=cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, workdesc.get_w(), workdesc.get_h()); + cairo_t* subcr=cairo_create(subimage); + cairo_save(subcr); + cairo_set_source_rgba(subcr, r, g, b, a); + // Now let's check if it is inverted + if(invert) + { + cairo_paint(subcr); + } + // Draw the region + cairo_translate(subcr, tx , ty); + cairo_scale(subcr, sx, sy); + + vector<Segment>::const_iterator iter=segments.begin(); + double t1x; + double t1y; + double t2x; + double t2y; + double p2x; + double p2y; + double p1x=iter->p1[0]; + double p1y=iter->p1[1]; + cairo_move_to(subcr, p1x, p1y); + for(;iter!=segments.end();++iter) + { + t1x=iter->t1[0]; + t1y=iter->t1[1]; + t2x=iter->t2[0]; + t2y=iter->t2[1]; + p1x=iter->p1[0]; + p1y=iter->p1[1]; + p2x=iter->p2[0]; + p2y=iter->p2[1]; + cairo_curve_to(subcr, p1x+t1x/3, p1y+t1y/3, p2x-t2x/3, p2y-t2y/3, p2x, p2y); + } + + cairo_close_path(subcr); + if(invert) + cairo_set_operator(subcr, CAIRO_OPERATOR_CLEAR); + else + cairo_set_operator(subcr, CAIRO_OPERATOR_OVER); + switch(winding_style) + { + case WINDING_NON_ZERO: + cairo_set_fill_rule(subcr, CAIRO_FILL_RULE_WINDING); + break; + default: + cairo_set_fill_rule(subcr, CAIRO_FILL_RULE_EVEN_ODD); + break; + } + if(!antialias) + cairo_set_antialias(subcr, CAIRO_ANTIALIAS_NONE); + + cairo_fill(subcr); + cairo_restore(subcr); + if(feather && quality!=10) + { + etl::surface<float> shapesurface; + shapesurface.set_wh(workdesc.get_w(),workdesc.get_h()); + shapesurface.clear(); + + CairoSurface cairosubimage(subimage); + if(!cairosubimage.map_cairo_image()) + { + synfig::info("map cairo image failed"); + return false; + } + // Extract the alpha values: + int x, y; + int wh(workdesc.get_h()), ww(workdesc.get_w()); + for(y=0; y<wh; y++) + for(x=0;x<ww;x++) + shapesurface[y][x]=cairosubimage[y][x].get_a()/CairoColor::ceil; + // Blue the alpha values + Blur(feather,feather,blurtype,cb)(shapesurface,workdesc.get_br()-workdesc.get_tl(),shapesurface); + // repaint the cairosubimage with the result + Color ccolor(color); + for(y=0; y<wh; y++) + for(x=0;x<ww;x++) + { + float a=shapesurface[y][x]; + ccolor.set_a(a); + ccolor.clamped(); + cairosubimage[y][x]=CairoColor(ccolor).premult_alpha(); + } + + cairosubimage.unmap_cairo_image(); + } + + // Put the (feathered) region on the surface + if(!is_solid_color()) // we need to render the context before + if(!context.accelerated_cairorender(surface,quality,renddesc,cb)) + { + if(cb) + cb->error(strprintf(__FILE__"%d: Accelerated Cairo Renderer Failure",__LINE__)); + cairo_destroy(cr); + cairo_destroy(subcr); + cairo_surface_destroy(subimage); + return false; + } + double px(tl[0]-workdesc.get_tl()[0]); + double py(tl[1]-workdesc.get_tl()[1]); + cairo_save(cr); + cairo_set_source_surface(cr, subimage, px, py ); + 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; +} + +///////// diff --git a/synfig-core/src/modules/mod_geometry/region.h b/synfig-core/src/modules/mod_geometry/region.h index 38e33f3..4694fc5 100644 --- a/synfig-core/src/modules/mod_geometry/region.h +++ b/synfig-core/src/modules/mod_geometry/region.h @@ -65,7 +65,7 @@ public: virtual Vocab get_param_vocab()const; virtual void set_time(Context context, Time time)const; virtual void set_time(Context context, Time time, Vector pos)const; - + virtual bool accelerated_cairorender(Context context,cairo_surface_t *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; }; /* === E N D =============================================================== */ ------------------------------------------------------------------------------ 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 Synfig-devl@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/synfig-devl