Author: Carlos Lopez <[email protected]>
Date: Thu Sep 6 20:40:17 2012 +0200
CurveWarp Layer: add support for Cairo render. It is a bit slower than the
software and for subsampled types there is banding around. Possibly it is due
to CairoColor resolution limitation
---
synfig-core/src/modules/lyr_std/curvewarp.cpp | 189 +++++++++++++++++++++++++
synfig-core/src/modules/lyr_std/curvewarp.h | 1 +
2 files changed, 190 insertions(+), 0 deletions(-)
diff --git a/synfig-core/src/modules/lyr_std/curvewarp.cpp
b/synfig-core/src/modules/lyr_std/curvewarp.cpp
index 3df5b39..c184556 100644
--- a/synfig-core/src/modules/lyr_std/curvewarp.cpp
+++ b/synfig-core/src/modules/lyr_std/curvewarp.cpp
@@ -597,3 +597,192 @@ CurveWarp::accelerated_render(Context context,Surface
*surface,int quality, cons
return true;
}
+
+/////
+
+bool
+CurveWarp::accelerated_cairorender(Context context,cairo_surface_t
*csurface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
+{
+ SuperCallback stageone(cb,0,9000,10000);
+ SuperCallback stagetwo(cb,9000,10000,10000);
+
+ int x,y;
+
+ const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
+ Point tl(renddesc.get_tl());
+ Point br(renddesc.get_br());
+ const int w(renddesc.get_w());
+ const int h(renddesc.get_h());
+
+ // find a bounding rectangle for the context we need to render
+ // todo: find a better way of doing this - this way doesn't work
+ Rect src_rect(transform(tl));
+ Point pos1, pos2;
+ Real dist, along;
+ Real min_dist(999999), max_dist(-999999), min_along(999999),
max_along(-999999);
+
+#define UPDATE_DIST \
+if (dist < min_dist) min_dist = dist; \
+if (dist > max_dist) max_dist = dist; \
+if (along < min_along) min_along = along; \
+if (along > max_along) max_along = along
+
+ // look along the top and bottom edges
+ pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
+ for (x = 0; x < w; x++, pos1[0] += pw, pos2[0] += pw)
+ {
+ src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
+ src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
+ }
+
+ // look along the left and right edges
+ pos1[0] = tl[0]; pos2[0] = br[0]; pos1[1] = pos2[1] = tl[1];
+ for (y = 0; y < h; y++, pos1[1] += ph, pos2[1] += ph)
+ {
+ src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
+ src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
+ }
+
+ // look along the diagonals
+ const int max_wh(std::max(w,h));
+ const Real inc_x((br[0]-tl[0])/max_wh),inc_y((br[1]-tl[1])/max_wh);
+ pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
+ for (x = 0; x < max_wh; x++, pos1[0] += inc_x, pos2[0] = pos1[0],
pos1[1]+=inc_y, pos2[1]-=inc_y)
+ {
+ src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
+ src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
+ }
+
+#if 0
+ // look at each blinepoint
+ std::vector<synfig::BLinePoint>::const_iterator iter;
+ for (iter=bline.begin(); iter!=bline.end(); iter++)
+ src_rect.expand(transform(iter->get_vertex()+origin, &dist,
&along)); UPDATE_DIST;
+#endif
+
+ Point src_tl(src_rect.get_min());
+ Point src_br(src_rect.get_max());
+
+ Vector ab((end_point - start_point).norm());
+ Angle::tan ab_angle(ab[1], ab[0]);
+
+ Real used_length = max_along - min_along;
+ Real render_width = max_dist - min_dist;
+
+ int src_w = (abs(used_length*Angle::cos(ab_angle).get()) +
+ abs(render_width*Angle::sin(ab_angle).get()))
/ abs(pw);
+ int src_h = (abs(used_length*Angle::sin(ab_angle).get()) +
+ abs(render_width*Angle::cos(ab_angle).get()))
/ abs(ph);
+
+ Real src_pw((src_br[0] - src_tl[0]) / src_w);
+ Real src_ph((src_br[1] - src_tl[1]) / src_h);
+
+ if (src_pw > abs(pw))
+ {
+ src_w = int((src_br[0] - src_tl[0]) / abs(pw));
+ src_pw = (src_br[0] - src_tl[0]) / src_w;
+ }
+
+ if (src_ph > abs(ph))
+ {
+ src_h = int((src_br[1] - src_tl[1]) / abs(ph));
+ src_ph = (src_br[1] - src_tl[1]) / src_h;
+ }
+
+#define MAXPIX 10000
+ if (src_w > MAXPIX) src_w = MAXPIX;
+ if (src_h > MAXPIX) src_h = MAXPIX;
+
+ // this is an attempt to remove artifacts around tile edges - the
+ // cubic interpolation uses at most 2 pixels either side of the
+ // target pixel, so add an extra 2 pixels around the tile on all
+ // sides
+ src_tl -= (Point(src_pw,src_ph)*2);
+ src_br += (Point(src_pw,src_ph)*2);
+ src_w += 4;
+ src_h += 4;
+ src_pw = (src_br[0] - src_tl[0]) / src_w;
+ src_ph = (src_br[1] - src_tl[1]) / src_h;
+
+ // set up a renddesc for the context to render
+ RendDesc src_desc(renddesc);
+ //src_desc.clear_flags();
+ src_desc.set_tl(src_tl);
+ src_desc.set_br(src_br);
+ src_desc.set_wh(src_w, src_h);
+
+ // render the context onto a new surface
+// Surface source;
+// source.set_wh(src_w,src_h);
+
+ cairo_surface_t* csource;
+
csource=cairo_surface_create_similar(csurface,CAIRO_CONTENT_COLOR_ALPHA, src_w,
src_h);
+ if(!context.accelerated_cairorender(csource,quality,src_desc,&stageone))
+ return false;
+ CairoSurface source(csource);
+ source.map_cairo_image();
+
+ CairoSurface surface(csurface);
+ surface.map_cairo_image();
+ float u,v;
+ Point pos, tmp;
+
+// surface->set_wh(w,h);
+// surface.clear();
+
+ if(quality<=4) // CUBIC
+ for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
+ {
+ for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
+ {
+ tmp=transform(pos);
+ u=(tmp[0]-src_tl[0])/src_pw;
+ v=(tmp[1]-src_tl[1])/src_ph;
+ if(u<0 || v<0 || u>=src_w || v>=src_h ||
isnan(u) || isnan(v))
+
surface[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
+ else
+
surface[y][x]=source.cubic_sample_cooked(u,v);
+ }
+ if((y&31)==0 && cb && !stagetwo.amount_complete(y,h))
return false;
+ }
+ else if (quality<=6) // INTERPOLATION_LINEAR
+ for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
+ {
+ for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
+ {
+ tmp=transform(pos);
+ u=(tmp[0]-src_tl[0])/src_pw;
+ v=(tmp[1]-src_tl[1])/src_ph;
+ if(u<0 || v<0 || u>=src_w || v>=src_h ||
isnan(u) || isnan(v))
+
surface[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
+ else
+
surface[y][x]=source.linear_sample_cooked(u,v);
+ }
+ if((y&31)==0 && cb && !stagetwo.amount_complete(y,h))
return false;
+ }
+ else // NEAREST_NEIGHBOR
+ for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
+ {
+ for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
+ {
+ tmp=transform(pos);
+ u=(tmp[0]-src_tl[0])/src_pw;
+ v=(tmp[1]-src_tl[1])/src_ph;
+ if(u<0 || v<0 || u>=src_w || v>=src_h ||
isnan(u) || isnan(v))
+
surface[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
+ else
+
surface[y][x]=source[floor_to_int(v)][floor_to_int(u)];
+ }
+ if((y&31)==0 && cb && !stagetwo.amount_complete(y,h))
return false;
+ }
+
+ surface.unmap_cairo_image();
+ source.unmap_cairo_image();
+ // Mark our progress as finished
+ if(cb && !cb->amount_complete(10000,10000))
+ return false;
+
+ return true;
+}
+
+/////
diff --git a/synfig-core/src/modules/lyr_std/curvewarp.h
b/synfig-core/src/modules/lyr_std/curvewarp.h
index a287887..9443845 100644
--- a/synfig-core/src/modules/lyr_std/curvewarp.h
+++ b/synfig-core/src/modules/lyr_std/curvewarp.h
@@ -70,6 +70,7 @@ public:
virtual Point transform(const Point &point_, Real *dist=NULL, Real
*along=0, int quality=10)const;
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;
synfig::Layer::Handle hit_check(synfig::Context context, const
synfig::Point &point)const;
virtual Vocab get_param_vocab()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