+ // 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);
+ 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<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]=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<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]=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<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]=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;
+ }