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=6b544e68d5291cddae4c01167d8e5da6b0ecf26c;hpb=5ae346e017651b10ea2b2b6e1391db5d4bc4243f;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 6b544e6..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 ======================================================= */ @@ -102,10 +97,8 @@ find_closest_to_bline(bool fast, const std::vector& bline,co bool first = true, last = false; extreme = false; - // printf(" loop\n"); for(;next!=end;iter=next++) { - // printf(" top\n"); // Setup the curve etl::hermite curve(iter->get_vertex(), next->get_vertex(), iter->get_tangent2(), next->get_tangent1()); float thisdist(0); @@ -128,36 +121,24 @@ find_closest_to_bline(bool fast, const std::vector& bline,co dist=thisdist; best_pos = pos; best_curve = curve; - // printf("set best_curve\n"); best_len = total_len; last = true; - // printf(" *last\n"); } } total_len += curve.length(); first = false; } - // printf(" after\n"); t = best_pos; if (fast) { len = best_len + best_curve.find_distance(0,best_curve.find_closest(fast, p)); - // printf("fast set len = %f + %f = %f\n", best_len, best_curve.find_distance(0,best_curve.find_closest(fast, p)), len); if (last && t > .99) extreme = true; } else { len = best_len + best_curve.find_distance(0,best_pos); - // printf("slow set len = %f + %f = %f\n", best_len, best_curve.find_distance(0,best_pos), len); - // printf("find_distance from 0 to %f is %f\n", best_pos, best_curve.find_distance(0,best_pos)); - // if (last) printf("last\n"); - - if (last && t > .999) - { - extreme = true; - // printf("extreme end\n"); - } + if (last && t == 1) extreme = true; } return ret; } @@ -169,22 +150,21 @@ CurveWarp::sync() { curve_length_=calculate_distance(bline); perp_ = (end_point - start_point).perp().norm(); - // printf("curve_length_ = %f\n", curve_length_); } CurveWarp::CurveWarp(): origin(0,0), - width(1), - start_point(-3,-1), - end_point(3,1), + perp_width(1), + start_point(-2.5,-0.5), + end_point(2.5,-0.3), fast(true) { bline.push_back(BLinePoint()); bline.push_back(BLinePoint()); bline[0].set_vertex(Point(-2.5,0)); - bline[1].set_vertex(Point(2.5,0)); - bline[0].set_tangent(Point(1, 1)); - bline[1].set_tangent(Point(1, -1)); + bline[1].set_vertex(Point( 2.5,0)); + bline[0].set_tangent(Point(1, 0.1)); + bline[1].set_tangent(Point(1, -0.1)); bline[0].set_width(1.0f); bline[1].set_width(1.0f); @@ -192,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; @@ -312,53 +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*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*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*width; + diff=diff.norm(); } else - diff=tangent.perp()*thickness*width; - - const Real mag(diff.inv_mag()); - supersample=supersample*mag; - diff*=mag*mag; - dist=(point_-origin - p1)*diff; - - len /= curve_length_; - - // printf("len %6.2f dist %6.2f\n", len, dist); - 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 @@ -374,7 +346,7 @@ CurveWarp::set_param(const String & param, const ValueBase &value) IMPORT(start_point); IMPORT(end_point); IMPORT(fast); - IMPORT(width); + IMPORT(perp_width); if(param=="bline" && value.get_type()==ValueBase::TYPE_LIST) { @@ -397,7 +369,7 @@ CurveWarp::get_param(const String & param)const EXPORT(end_point); EXPORT(bline); EXPORT(fast); - EXPORT(width); + EXPORT(perp_width); EXPORT_NAME(); EXPORT_VERSION(); @@ -413,11 +385,13 @@ CurveWarp::get_param_vocab()const ret.push_back(ParamDesc("origin") .set_local_name(_("Origin"))); - ret.push_back(ParamDesc("width") - .set_local_name(_("Width"))); + ret.push_back(ParamDesc("perp_width") + .set_local_name(_("Width")) + .set_origin("start_point")); ret.push_back(ParamDesc("start_point") - .set_local_name(_("Start Point"))); + .set_local_name(_("Start Point")) + .set_connect("end_point")); ret.push_back(ParamDesc("end_point") .set_local_name(_("End Point"))); @@ -443,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))