Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_05 / synfig-core / src / modules / lyr_std / warp.cpp
1 /*! ========================================================================
2 ** Synfig
3 ** Template File
4 ** $Id: warp.cpp,v 1.2 2005/01/24 05:00:18 darco Exp $
5 **
6 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
7 **
8 **      This package is free software; you can redistribute it and/or
9 **      modify it under the terms of the GNU General Public License as
10 **      published by the Free Software Foundation; either version 2 of
11 **      the License, or (at your option) any later version.
12 **
13 **      This package is distributed in the hope that it will be useful,
14 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 **      General Public License for more details.
17 **
18 ** === N O T E S ===========================================================
19 **
20 ** ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "warp.h"
32 #include <synfig/string.h>
33 #include <synfig/time.h>
34 #include <synfig/context.h>
35 #include <synfig/paramdesc.h>
36 #include <synfig/renddesc.h>
37 #include <synfig/surface.h>
38 #include <synfig/value.h>
39 #include <synfig/valuenode.h>
40 #include <synfig/transform.h>
41 #include <ETL/misc>
42
43 #endif
44
45 /* === M A C R O S ========================================================= */
46
47 /* === G L O B A L S ======================================================= */
48
49 SYNFIG_LAYER_INIT(Warp);
50 SYNFIG_LAYER_SET_NAME(Warp,"warp");
51 SYNFIG_LAYER_SET_LOCAL_NAME(Warp,_("Warp"));
52 SYNFIG_LAYER_SET_CATEGORY(Warp,_("Distortions"));
53 SYNFIG_LAYER_SET_VERSION(Warp,"0.1");
54 SYNFIG_LAYER_SET_CVS_ID(Warp,"$Id: warp.cpp,v 1.2 2005/01/24 05:00:18 darco Exp $");
55
56 /* === P R O C E D U R E S ================================================= */
57
58 /* === M E T H O D S ======================================================= */
59
60 /* === E N T R Y P O I N T ================================================= */
61
62 Warp::Warp():
63         src_tl  (-2,2),
64         src_br  (2,-2),
65         dest_tl (-1.8,2.1),
66         dest_tr (1.8,2.1),
67         dest_br (2.2,-2),
68         dest_bl (-2.2,-2),
69         clip    (true)
70 {
71         sync();
72         horizon=4;
73 }
74
75 Warp::~Warp()
76 {
77 }
78
79 inline Point
80 Warp::transform_forward(const Point& p)const
81 {
82         return Point(
83                 (inv_matrix[0][0]*p[0] + inv_matrix[0][1]*p[1] + inv_matrix[0][2])/(inv_matrix[2][0]*p[0] + inv_matrix[2][1]*p[1] + inv_matrix[2][2]),
84                 (inv_matrix[1][0]*p[0] + inv_matrix[1][1]*p[1] + inv_matrix[1][2])/(inv_matrix[2][0]*p[0] + inv_matrix[2][1]*p[1] + inv_matrix[2][2])
85         );
86 }
87
88 inline Point
89 Warp::transform_backward(const Point& p)const
90 {
91         return Point(
92                 (matrix[0][0]*p[0] + matrix[0][1]*p[1] + matrix[0][2])/(matrix[2][0]*p[0] + matrix[2][1]*p[1] + matrix[2][2]),
93                 (matrix[1][0]*p[0] + matrix[1][1]*p[1] + matrix[1][2])/(matrix[2][0]*p[0] + matrix[2][1]*p[1] + matrix[2][2])
94         );
95 }
96
97 inline Real
98 Warp::transform_forward_z(const Point& p)const
99 {
100         return inv_matrix[2][0]*p[0] + inv_matrix[2][1]*p[1] + inv_matrix[2][2];
101 }
102
103 inline Real
104 Warp::transform_backward_z(const Point& p)const
105 {
106         return matrix[2][0]*p[0] + matrix[2][1]*p[1] + matrix[2][2];
107 }
108
109 /*
110 #define transform_forward(p) Point(     \
111                 cache_a*p[0] + cache_b*p[1] + cache_c*p[0]*p[1] + cache_d,      \
112                 cache_e*p[0] + cache_f*p[1] + cache_i*p[0]*p[1] + cache_j )
113
114 #define transform_backward(p) Point(    \
115                 cache_a*p[0] + cache_b*p[1] + cache_c*p[0]*p[1] + cache_d,      \
116                 cache_e*p[0] + cache_f*p[1] + cache_i*p[0]*p[1] + cache_j )
117 */
118
119 #define triangle_area(a,b,c)    (0.5*(-b[0]*a[1]+c[0]*a[1]+a[0]*b[1]-c[0]*b[1]-a[0]*c[1]+b[0]*c[1]))
120 #define quad_area(a,b,c,d) (triangle_area(a,b,c)+triangle_area(a,c,d))
121
122 Real mat3_determinant(Real matrix[3][3])
123 {
124   Real ret;
125
126   ret  = (matrix[0][0] *
127                   (matrix[1][1] * matrix[2][2] -
128                    matrix[1][2] * matrix[2][1]));
129   ret -= (matrix[1][0] *
130                   (matrix[0][1] * matrix[2][2] -
131                    matrix[0][2] * matrix[2][1]));
132   ret += (matrix[2][0] *
133                   (matrix[0][1] * matrix[1][2] -
134                    matrix[0][2] * matrix[1][1]));
135
136 return ret;
137 }
138
139 void mat3_invert(Real in[3][3], Real out[3][3])
140 {
141   Real det(mat3_determinant(in));
142
143         if (det == 0.0)
144     return;
145
146   det = 1.0 / det;
147
148   out[0][0] =   (in[1][1] * in[2][2] -
149                        in[1][2] * in[2][1]) * det;
150
151   out[1][0] = - (in[1][0] * in[2][2] -
152                        in[1][2] * in[2][0]) * det;
153
154   out[2][0] =   (in[1][0] * in[2][1] -
155                        in[1][1] * in[2][0]) * det;
156
157   out[0][1] = - (in[0][1] * in[2][2] -
158                        in[0][2] * in[2][1]) * det;
159
160   out[1][1] =   (in[0][0] * in[2][2] -
161                        in[0][2] * in[2][0]) * det;
162
163   out[2][1] = - (in[0][0] * in[2][1] -
164                        in[0][1] * in[2][0]) * det;
165
166   out[0][2] =   (in[0][1] * in[1][2] -
167                        in[0][2] * in[1][1]) * det;
168
169   out[1][2] = - (in[0][0] * in[1][2] -
170                        in[0][2] * in[1][0]) * det;
171
172   out[2][2] =   (in[0][0] * in[1][1] -
173                        in[0][1] * in[1][0]) * det;
174
175 }
176
177 void
178 Warp::sync()
179 {
180 /*      cache_a=(-dest_tl[0]+dest_tr[0])/(src_br[1]-src_tl[1]);
181         cache_b=(-dest_tl[0]+dest_bl[0])/(src_br[0]-src_tl[0]);
182         cache_c=(dest_tl[0]-dest_tr[0]+dest_br[0]-dest_bl[0])/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
183         cache_d=dest_tl[0];
184
185         cache_e=(-dest_tl[1]+dest_tr[1])/(src_br[0]-src_tl[0]);
186         cache_f=(-dest_tl[1]+dest_bl[1])/(src_br[1]-src_tl[1]);
187         cache_i=(dest_tl[1]-dest_tr[1]+dest_br[1]-dest_bl[1])/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
188         cache_j=dest_tl[1];     
189 */
190         
191 /*      matrix[2][0]=(dest_tl[0]-dest_tr[0]+dest_br[0]-dest_bl[0])/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
192         matrix[2][1]=(dest_tl[1]-dest_tr[1]+dest_br[1]-dest_bl[1])/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
193         matrix[2][2]=quad_area(dest_tl,dest_tr,dest_br,dest_bl)/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
194         
195         matrix[0][0]=-(-dest_tl[1]+dest_tr[1])/(src_br[0]-src_tl[0]);
196         matrix[0][1]=-(-dest_tl[1]+dest_bl[1])/(src_br[1]-src_tl[1]);
197
198         matrix[1][0]=-(-dest_tl[0]+dest_tr[0])/(src_br[1]-src_tl[1]);
199         matrix[1][1]=-(-dest_tl[0]+dest_bl[0])/(src_br[0]-src_tl[0]);
200
201         matrix[0][2]=matrix[0][0]*dest_tl[0] + matrix[0][1]*dest_tl[1];
202         matrix[1][2]=matrix[1][0]*dest_tl[0] + matrix[1][1]*dest_tl[1];
203 */
204
205 #define matrix tmp
206         Real tmp[3][3];
207
208         const Real& x1(min(src_br[0],src_tl[0]));
209         const Real& y1(min(src_br[1],src_tl[1]));
210         const Real& x2(max(src_br[0],src_tl[0]));
211         const Real& y2(max(src_br[1],src_tl[1]));
212         
213         Real tx1(dest_bl[0]);
214         Real ty1(dest_bl[1]);
215         Real tx2(dest_br[0]);
216         Real ty2(dest_br[1]);
217         Real tx3(dest_tl[0]);
218         Real ty3(dest_tl[1]);
219         Real tx4(dest_tr[0]);
220         Real ty4(dest_tr[1]);
221
222         if(src_br[0]<src_tl[0])
223                 swap(tx3,tx4),swap(ty3,ty4),swap(tx1,tx2),swap(ty1,ty2);
224
225         if(src_br[1]>src_tl[1])
226                 swap(tx3,tx1),swap(ty3,ty1),swap(tx4,tx2),swap(ty4,ty2);
227
228         Real scalex;
229         Real scaley;
230
231   scalex = scaley = 1.0;
232
233   if ((x2 - x1) > 0)
234     scalex = 1.0 / (Real) (x2 - x1);
235
236   if ((y2 - y1) > 0)
237     scaley = 1.0 / (Real) (y2 - y1);
238
239   /* Determine the perspective transform that maps from
240    * the unit cube to the transformed coordinates
241    */
242   {
243     Real dx1, dx2, dx3, dy1, dy2, dy3;
244
245     dx1 = tx2 - tx4;
246     dx2 = tx3 - tx4;
247     dx3 = tx1 - tx2 + tx4 - tx3;
248
249     dy1 = ty2 - ty4;
250     dy2 = ty3 - ty4;
251     dy3 = ty1 - ty2 + ty4 - ty3;
252
253     /*  Is the mapping affine?  */
254     if ((dx3 == 0.0) && (dy3 == 0.0))
255       {
256         matrix[0][0] = tx2 - tx1;
257         matrix[0][1] = tx4 - tx2;
258         matrix[0][2] = tx1;
259         matrix[1][0] = ty2 - ty1;
260         matrix[1][1] = ty4 - ty2;
261         matrix[1][2] = ty1;
262         matrix[2][0] = 0.0;
263         matrix[2][1] = 0.0;
264       }
265     else
266       {
267         Real det1, det2;
268
269         det1 = dx3 * dy2 - dy3 * dx2;
270         det2 = dx1 * dy2 - dy1 * dx2;
271
272         if (det1 == 0.0 && det2 == 0.0)
273           matrix[2][0] = 1.0;
274         else
275           matrix[2][0] = det1 / det2;
276
277         det1 = dx1 * dy3 - dy1 * dx3;
278
279         if (det1 == 0.0 && det2 == 0.0)
280           matrix[2][1] = 1.0;
281         else
282           matrix[2][1] = det1 / det2;
283
284         matrix[0][0] = tx2 - tx1 + matrix[2][0] * tx2;
285         matrix[0][1] = tx3 - tx1 + matrix[2][1] * tx3;
286         matrix[0][2] = tx1;
287
288         matrix[1][0] = ty2 - ty1 + matrix[2][0] * ty2;
289         matrix[1][1] = ty3 - ty1 + matrix[2][1] * ty3;
290         matrix[1][2] = ty1;
291       }
292
293     matrix[2][2] = 1.0;
294   }
295 #undef matrix
296   
297         Real scaletrans[3][3]={
298                         { scalex, 0, -x1*scalex },
299                         { 0, scaley, -y1*scaley },
300                         { 0, 0, 1 }
301         };
302
303         Real t1,t2,t3;
304
305         for (int i = 0; i < 3; i++)
306     {
307       t1 = tmp[i][0];
308       t2 = tmp[i][1];
309       t3 = tmp[i][2];
310
311       for (int j = 0; j < 3; j++)
312         {
313           matrix[i][j]  = t1 * scaletrans[0][j];
314           matrix[i][j] += t2 * scaletrans[1][j];
315           matrix[i][j] += t3 * scaletrans[2][j];
316         }
317     }
318
319         mat3_invert(matrix, inv_matrix);
320 /*
321         gimp_matrix3_identity  (result);
322   gimp_matrix3_translate (result, -x1, -y1);
323   gimp_matrix3_scale     (result, scalex, scaley);
324   gimp_matrix3_mult      (&matrix, result);
325 */
326 }
327
328 bool
329 Warp::set_param(const String & param, const ValueBase &value)
330 {
331         IMPORT_PLUS(src_tl,sync());
332         IMPORT_PLUS(src_br,sync());
333         IMPORT_PLUS(dest_tl,sync());
334         IMPORT_PLUS(dest_tr,sync());
335         IMPORT_PLUS(dest_bl,sync());
336         IMPORT_PLUS(dest_br,sync());
337         IMPORT(clip);
338         IMPORT(horizon);
339         
340         return false;
341 }
342
343 ValueBase
344 Warp::get_param(const String &param)const
345 {
346         EXPORT(src_tl);
347         EXPORT(src_br);
348         EXPORT(dest_tl);
349         EXPORT(dest_tr);
350         EXPORT(dest_bl);
351         EXPORT(dest_br);
352         EXPORT(clip);
353         EXPORT(horizon);
354         
355         EXPORT_NAME();
356         EXPORT_VERSION();
357                 
358         return ValueBase();     
359 }
360
361 Layer::Vocab
362 Warp::get_param_vocab()const
363 {
364         Layer::Vocab ret;
365         
366         ret.push_back(ParamDesc("src_tl")
367                 .set_local_name(_("Source TL"))
368                 .set_box("src_br")
369         );
370
371         ret.push_back(ParamDesc("src_br")
372                 .set_local_name(_("Source BR"))
373         );
374
375         ret.push_back(ParamDesc("dest_tl")
376                 .set_local_name(_("Dest TL"))
377                 .set_connect("dest_tr")
378         );
379
380         ret.push_back(ParamDesc("dest_tr")
381                 .set_local_name(_("Dest TR"))
382                 .set_connect("dest_br")
383         );
384
385         ret.push_back(ParamDesc("dest_br")
386                 .set_local_name(_("Dest BR"))
387                 .set_connect("dest_bl")
388         );
389
390         ret.push_back(ParamDesc("dest_bl")
391                 .set_local_name(_("Dest BL"))
392                 .set_connect("dest_tl")
393         );
394
395         ret.push_back(ParamDesc("clip")
396                 .set_local_name(_("Clip"))
397         );
398
399         ret.push_back(ParamDesc("horizon")
400                 .set_local_name(_("Horizon"))
401         );
402
403         return ret;
404 }
405
406
407 class Warp_Trans : public Transform
408 {
409         etl::handle<const Warp> layer;
410 public:
411         Warp_Trans(const Warp* x):Transform(x->get_guid()),layer(x) { }
412         
413         synfig::Vector perform(const synfig::Vector& x)const
414         {
415                 return layer->transform_backward(x);
416                 //Point pos(x-layer->origin);
417                 //return Point(layer->cos_val*pos[0]-layer->sin_val*pos[1],layer->sin_val*pos[0]+layer->cos_val*pos[1])+layer->origin;
418         }
419         
420         synfig::Vector unperform(const synfig::Vector& x)const
421         {
422
423                 return layer->transform_forward(x);
424                 //Point pos(x-layer->origin);
425                 //return Point(layer->cos_val*pos[0]+layer->sin_val*pos[1],-layer->sin_val*pos[0]+layer->cos_val*pos[1])+layer->origin;
426         }
427 };
428 etl::handle<Transform>
429 Warp::get_transform()const
430 {
431         return new Warp_Trans(this);
432 }
433
434 synfig::Layer::Handle
435 Warp::hit_check(synfig::Context context, const synfig::Point &p)const
436 {
437         Point newpos(transform_forward(p));
438
439         if(clip)
440         {
441                 Rect rect(src_tl,src_br);
442                 if(!rect.is_inside(newpos))
443                         return 0;
444         }
445         
446         return context.hit_check(newpos);
447 }
448
449 Color
450 Warp::get_color(Context context, const Point &p)const
451 {
452         Point newpos(transform_forward(p));
453
454         if(clip)
455         {
456                 Rect rect(src_tl,src_br);
457                 if(!rect.is_inside(newpos))
458                         return Color::alpha();
459         }
460
461         const float z(transform_backward_z(newpos));
462         if(z>0 && z<horizon)
463                 return context.get_color(newpos);
464         else
465                 return Color::alpha();
466 }
467
468 //#define ACCEL_WARP_IS_BROKEN 1
469
470 bool
471 Warp::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
472 {
473         SuperCallback stageone(cb,0,9000,10000);
474         SuperCallback stagetwo(cb,9000,10000,10000);
475
476         Real pw=(renddesc.get_w())/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
477         Real ph=(renddesc.get_h())/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
478         
479         if(cb && !cb->amount_complete(0,10000))
480                 return false;
481         
482         Point tl(renddesc.get_tl());
483         Point br(renddesc.get_br());
484
485         Rect bounding_rect;
486         
487         Rect render_rect(tl,br);
488         Rect clip_rect(Rect::full_plane());
489         Rect dest_rect(dest_tl,dest_br); dest_rect.expand(dest_tr).expand(dest_bl);
490
491         Real zoom_factor(1.0);
492
493         // Quick exclusion clip, if necessary
494         if(clip && !intersect(render_rect,dest_rect))
495         {
496                 surface->set_wh(renddesc.get_w(),renddesc.get_h());
497                 surface->clear();
498                 return true;
499         }
500         
501         {
502                 Rect other(render_rect);
503                 if(clip)
504                         other&=dest_rect;
505                 
506                 Point min(other.get_min());
507                 Point max(other.get_max());
508                 
509                 bool init_point_set=false;
510                 
511                 Point trans_point[4];
512                 Point p;
513                 Real trans_z[4];
514                 Real z,minz(10000000000000.0f),maxz(0);
515                 
516                 
517                 p=transform_forward(min);
518                 z=transform_backward_z(p);
519                 if(z>0 && z<horizon*2)
520                 {
521                         if(init_point_set)
522                                 bounding_rect.expand(p);
523                         else
524                                 bounding_rect=Rect(p);
525                         init_point_set=true;
526                         maxz=std::max(maxz,z);
527                         minz=std::min(minz,z);                  
528                 }
529                 
530                 p=transform_forward(max);
531                 z=transform_backward_z(p);
532                 if(z>0 && z<horizon*2)
533                 {
534                         if(init_point_set)
535                                 bounding_rect.expand(p);
536                         else
537                                 bounding_rect=Rect(p);
538                         init_point_set=true;
539                         maxz=std::max(maxz,z);
540                         minz=std::min(minz,z);                  
541                 }
542
543                 swap(min[1],max[1]);
544
545                 p=transform_forward(min);
546                 z=transform_backward_z(p);
547                 if(z>0 && z<horizon*2)
548                 {
549                         if(init_point_set)
550                                 bounding_rect.expand(p);
551                         else
552                                 bounding_rect=Rect(p);
553                         init_point_set=true;
554                         maxz=std::max(maxz,z);
555                         minz=std::min(minz,z);                  
556                 }
557                 
558                 p=transform_forward(max);
559                 z=transform_backward_z(p);
560                 if(z>0 && z<horizon*2)
561                 {
562                         if(init_point_set)
563                                 bounding_rect.expand(p);
564                         else
565                                 bounding_rect=Rect(p);
566                         init_point_set=true;
567                         maxz=std::max(maxz,z);
568                         minz=std::min(minz,z);                  
569                 }
570                 
571                 if(!init_point_set)
572                 {
573                         surface->set_wh(renddesc.get_w(),renddesc.get_h());
574                         surface->clear();
575                         return true;
576                 }
577                 zoom_factor=(1+(maxz-minz));
578                 
579         }
580
581 #ifdef ACCEL_WARP_IS_BROKEN
582         return Layer::accelerated_render(context,surface,quality,renddesc, cb);
583 #else
584         
585         /*swap(tl[1],br[1]);
586         bounding_rect
587                 .expand(transform_forward(tl))
588                 .expand(transform_forward(br))
589         ;
590         swap(tl[1],br[1]);*/
591         
592         //synfig::warning("given window: [%f,%f]-[%f,%f] %dx%d",tl[0],tl[1],br[0],br[1],renddesc.get_w(),renddesc.get_h());
593         //synfig::warning("Projected: [%f,%f]-[%f,%f]",bounding_rect.get_min()[0],bounding_rect.get_min()[1],bounding_rect.get_max()[0],bounding_rect.get_max()[1]);
594
595         // If we are clipping, then go ahead and clip to the
596         // source rectangle
597         if(clip)
598                 clip_rect&=Rect(src_tl,src_br);
599                 
600         // Bound ourselves to the bounding rectangle of
601         // what is under us
602         clip_rect&=context.get_full_bounding_rect();//.expand_x(abs(zoom_factor/pw)).expand_y(abs(zoom_factor/ph));
603
604         bounding_rect&=clip_rect;
605         
606         Point min_point(bounding_rect.get_min());
607         Point max_point(bounding_rect.get_max());
608         
609         
610         if(tl[0]>br[0])
611         {
612                 tl[0]=max_point[0];
613                 br[0]=min_point[0];
614         }
615         else
616         {
617                 br[0]=max_point[0];
618                 tl[0]=min_point[0];
619         }
620         if(tl[1]>br[1])
621         {
622                 tl[1]=max_point[1];
623                 br[1]=min_point[1];
624         }
625         else
626         {
627                 br[1]=max_point[1];
628                 tl[1]=min_point[1];
629         }
630         
631         
632
633         const int tmp_d(max(renddesc.get_w(),renddesc.get_h()));
634         Real src_pw=(tmp_d*zoom_factor)/(br[0]-tl[0]);
635         Real src_ph=(tmp_d*zoom_factor)/(br[1]-tl[1]);
636
637         
638         RendDesc desc(renddesc);
639         desc.clear_flags();
640         //desc.set_flags(RendDesc::PX_ASPECT);
641         desc.set_tl(tl);
642         desc.set_br(br);
643         desc.set_wh(ceil_to_int(src_pw*(br[0]-tl[0])),ceil_to_int(src_ph*(br[1]-tl[1])));
644
645         //synfig::warning("surface to render: [%f,%f]-[%f,%f] %dx%d",desc.get_tl()[0],desc.get_tl()[1],desc.get_br()[0],desc.get_br()[1],desc.get_w(),desc.get_h());
646         if(desc.get_w()==0 && desc.get_h()==0)
647         {
648                 surface->set_wh(renddesc.get_w(),renddesc.get_h());
649                 surface->clear();
650                 return true;
651         }
652
653         // Recalculate the pixel widths for the src renddesc
654         src_pw=(desc.get_w())/(desc.get_br()[0]-desc.get_tl()[0]);
655         src_ph=(desc.get_h())/(desc.get_br()[1]-desc.get_tl()[1]);
656
657         
658         Surface source;
659         source.set_wh(desc.get_w(),desc.get_h());
660
661         if(!context.accelerated_render(&source,quality,desc,&stageone))
662                 return false;
663         
664         surface->set_wh(renddesc.get_w(),renddesc.get_h());
665         surface->clear();
666         
667         Surface::pen pen(surface->begin());
668
669         if(quality<=4)
670         {
671                 // CUBIC
672                 int x,y;
673                 float u,v;
674                 Point point,tmp;
675                 for(y=0,point[1]=renddesc.get_tl()[1];y<surface->get_h();y++,pen.inc_y(),pen.dec_x(x),point[1]+=1.0/ph)
676                 {
677                         for(x=0,point[0]=renddesc.get_tl()[0];x<surface->get_w();x++,pen.inc_x(),point[0]+=1.0/pw)
678                         {
679                                 tmp=transform_forward(point);
680                                 const float z(transform_backward_z(tmp));
681                                 if(!clip_rect.is_inside(tmp) || !(z>0 && z<horizon))
682                                 {
683                                         (*surface)[y][x]=Color::alpha();
684                                         continue;
685                                 }
686                                 
687                                 u=(tmp[0]-tl[0])*src_pw;
688                                 v=(tmp[1]-tl[1])*src_ph;
689                                 
690                                 if(u<0 || v<0 || u>=source.get_w() || v>=source.get_h() || isnan(u) || isnan(v))
691                                 {
692                                         (*surface)[y][x]=context.get_color(tmp);
693                                 }
694                                 else                            
695                                         (*surface)[y][x]=source.cubic_sample(u,v);
696                         }
697                         if(y&31==0 && cb)
698                         {
699                                 if(!stagetwo.amount_complete(y,surface->get_h()))
700                                         return false;
701                         }
702                 }
703         }
704         else
705         if(quality<=6)
706         {
707                 // INTERPOLATION_LINEAR
708                 int x,y;
709                 float u,v;
710                 Point point,tmp;
711                 for(y=0,point[1]=renddesc.get_tl()[1];y<surface->get_h();y++,pen.inc_y(),pen.dec_x(x),point[1]+=1.0/ph)
712                 {
713                         for(x=0,point[0]=renddesc.get_tl()[0];x<surface->get_w();x++,pen.inc_x(),point[0]+=1.0/pw)
714                         {
715                                 tmp=transform_forward(point);
716                                 const float z(transform_backward_z(tmp));
717                                 if(!clip_rect.is_inside(tmp) || !(z>0 && z<horizon))
718                                 {
719                                         (*surface)[y][x]=Color::alpha();
720                                         continue;
721                                 }
722                                 
723                                 u=(tmp[0]-tl[0])*src_pw;
724                                 v=(tmp[1]-tl[1])*src_ph;
725                                 
726                                 if(u<0 || v<0 || u>=source.get_w() || v>=source.get_h() || isnan(u) || isnan(v))
727                                 {
728                                         if(clip)
729                                                 (*surface)[y][x]=Color::alpha();
730                                         else
731                                                 (*surface)[y][x]=context.get_color(tmp);
732                                 }
733                                 else
734                                         (*surface)[y][x]=source.linear_sample(u,v);
735                         }
736                         if(y&31==0 && cb)
737                         {
738                                 if(!stagetwo.amount_complete(y,surface->get_h()))
739                                         return false;
740                         }
741                 }
742         }
743         else
744         {
745                 // NEAREST_NEIGHBOR
746                 int x,y;
747                 float u,v;
748                 Point point,tmp;
749                 for(y=0,point[1]=renddesc.get_tl()[1];y<surface->get_h();y++,pen.inc_y(),pen.dec_x(x),point[1]+=1.0/ph)
750                 {
751                         for(x=0,point[0]=renddesc.get_tl()[0];x<surface->get_w();x++,pen.inc_x(),point[0]+=1.0/pw)
752                         {
753                                 tmp=transform_forward(point);
754                                 const float z(transform_backward_z(tmp));
755                                 if(!clip_rect.is_inside(tmp) || !(z>0 && z<horizon))
756                                 {
757                                         (*surface)[y][x]=Color::alpha();
758                                         continue;
759                                 }
760                                 
761                                 u=(tmp[0]-tl[0])*src_pw;
762                                 v=(tmp[1]-tl[1])*src_ph;
763                                 
764                                 if(u<0 || v<0 || u>=source.get_w() || v>=source.get_h() || isnan(u) || isnan(v))
765                                 {
766                                         if(clip)
767                                                 (*surface)[y][x]=Color::alpha();
768                                         else
769                                                 (*surface)[y][x]=context.get_color(tmp);
770                                 }
771                                 else
772                                 //pen.set_value(source[v][u]);
773                                 (*surface)[y][x]=source[floor_to_int(v)][floor_to_int(u)];
774                         }
775                         if(y&31==0 && cb)
776                         {
777                                 if(!stagetwo.amount_complete(y,surface->get_h()))
778                                         return false;
779                         }
780                 }
781         }
782
783 #endif
784
785         if(cb && !cb->amount_complete(10000,10000)) return false;
786
787         return true;
788 }
789
790 synfig::Rect
791 Warp::get_bounding_rect()const
792 {       
793         return Rect::full_plane();
794 }
795
796 synfig::Rect
797 Warp::get_full_bounding_rect(Context context)const
798 {
799 //      return Rect::full_plane();
800         
801         Rect under(context.get_full_bounding_rect());
802
803         if(clip)
804         {
805                 under&=Rect(src_tl,src_br);
806         }
807         
808         return get_transform()->perform(under);
809         
810         /*
811         Rect under(context.get_full_bounding_rect());
812         Rect ret(Rect::zero());
813         
814         if(under.area()==HUGE_VAL)
815                 return Rect::full_plane();
816         
817         ret.expand(
818                 transform_backward(
819                         under.get_min()
820                 )
821         );
822         ret.expand(
823                 transform_backward(
824                         under.get_max()
825                 )
826         );
827         ret.expand(
828                 transform_backward(
829                         Vector(
830                                 under.get_min()[0],
831                                 under.get_max()[1]
832                         )
833                 )
834         );
835         ret.expand(
836                 transform_backward(
837                         Vector(
838                                 under.get_max()[0],
839                                 under.get_min()[1]
840                         )
841                 )
842         );
843
844         if(ret.area()==HUGE_VAL)
845                 return Rect::full_plane();
846
847         return ret;
848         */
849 }