X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-core%2Ftrunk%2Fsrc%2Fmodules%2Flyr_std%2Fcurvewarp.cpp;h=82c213d97f55a721f1717d2df0a09cdafb0fcac0;hb=9459638ad6797b8139f1e9f0715c96076dbf0890;hp=3a10076817421df2da2f15ce1db693f1e531150c;hpb=9ad41b0d8487c57ababec0da386adb620e7f06a7;p=synfig.git diff --git a/synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp b/synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp index 3a10076..82c213d 100644 --- a/synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp +++ b/synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp @@ -34,16 +34,10 @@ #include "curvewarp.h" -#include -#include #include #include -#include #include -#include #include -#include -#include #include #endif @@ -51,6 +45,7 @@ /* === M A C R O S ========================================================= */ #define FAKE_TANGENT_STEP 0.000001 +#define TOO_THIN 0.01 /* === G L O B A L S ======================================================= */ @@ -177,13 +172,12 @@ CurveWarp::CurveWarp(): } inline Point -CurveWarp::transform(const Point &point_, int quality, float supersample)const +CurveWarp::transform(const Point &point_, Real *dist, Real *along, int quality)const { Vector tangent; Vector diff; Point p1; Real thickness; - Real dist; bool edge_case = false; float len(0); bool extreme; @@ -297,51 +291,46 @@ CurveWarp::transform(const Point &point_, int quality, float supersample)const thickness=(next->get_width()-iter->get_width())*t+iter->get_width(); } + if (thickness < TOO_THIN && thickness > -TOO_THIN) + { + if (thickness > 0) thickness = TOO_THIN; + else thickness = -TOO_THIN; + } + if (extreme) { - Vector tangent, perp; + Vector tangent; if (t < 0.5) { - synfig::BLinePoint start(bline[0]); - // Point a(start.get_vertex()); - tangent = start.get_tangent1().norm(); - diff = tangent.perp()*thickness*perp_width; - len = (point_-origin - p1)*tangent; + std::vector::const_iterator iter(bline.begin()); + tangent = iter->get_tangent1().norm(); + len = 0; } else { - std::vector::const_iterator iter; - iter=bline.end(); - iter--; + std::vector::const_iterator iter(--bline.end()); tangent = iter->get_tangent2().norm(); - diff = tangent.perp()*thickness*perp_width; - len = (point_-origin - p1)*tangent + curve_length_; + len = curve_length_; } + len += (point_-origin - p1)*tangent; + diff = tangent.perp(); } else if (edge_case) { diff=(p1-(point_-origin)); if(diff*tangent.perp()<0) diff=-diff; - diff=diff.norm()*thickness*perp_width; + diff=diff.norm(); } else - diff=tangent.perp()*thickness*perp_width; - - const Real mag(diff.inv_mag()); - supersample=supersample*mag; - diff*=mag*mag; - dist=(point_-origin - p1)*diff; - - len /= curve_length_; - - return (start_point + (end_point - start_point) * len) + perp_ * dist; -} - -float -CurveWarp::calc_supersample(const synfig::Point &/*x*/, float pw,float /*ph*/)const -{ - return pw; + diff=tangent.perp(); + + // diff is a unit vector perpendicular to the bline + const Real unscaled_distance((point_-origin - p1)*diff); + if (dist) *dist = unscaled_distance; + if (along) *along = len; + return ((start_point + (end_point - start_point) * len / curve_length_) + + perp_ * unscaled_distance/(thickness*perp_width)); } synfig::Layer::Handle @@ -428,25 +417,171 @@ CurveWarp::get_color(Context context, const Point &point)const bool CurveWarp::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const { - SuperCallback supercb(cb,0,9500,10000); - - if(!context.accelerated_render(surface,quality,renddesc,&supercb)) - return false; + 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 pos; Point tl(renddesc.get_tl()); - const int w(surface->get_w()); - const int h(surface->get_h()); + 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; + } - for(y=0,pos[1]=tl[1];y::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); + if(!context.accelerated_render(&source,quality,src_desc,&stageone)) + return false; + + 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=src_w || v>=src_h || isnan(u) || isnan(v)) + (*surface)[y][x]=context.get_color(tmp); + else + (*surface)[y][x]=source.cubic_sample(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=src_w || v>=src_h || isnan(u) || isnan(v)) + (*surface)[y][x]=context.get_color(tmp); + else + (*surface)[y][x]=source.linear_sample(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=src_w || v>=src_h || isnan(u) || isnan(v)) + (*surface)[y][x]=context.get_color(tmp); + 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; + } // Mark our progress as finished if(cb && !cb->amount_complete(10000,10000))