Moved an apostrophe.
[synfig.git] / synfig-core / trunk / src / synfig / layer_shape.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file layer_shape.cpp
3 **      \brief Template Header
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "layer_shape.h"
33 #include "string.h"
34 #include "time.h"
35 #include "context.h"
36 #include "paramdesc.h"
37 #include "renddesc.h"
38 #include "surface.h"
39 #include "value.h"
40 #include "valuenode.h"
41 #include "float.h"
42 #include "blur.h"
43
44 #include "curve_helper.h"
45
46 #include <vector>
47
48 #include <deque>
49
50 #endif
51
52 /* === U S I N G =========================================================== */
53
54 using namespace synfig;
55 using namespace std;
56 using namespace etl;
57
58 /* === G L O B A L S ======================================================= */
59
60 SYNFIG_LAYER_INIT(Layer_Shape);
61 SYNFIG_LAYER_SET_NAME(Layer_Shape,"shape");
62 SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Shape,_("Shape"));
63 SYNFIG_LAYER_SET_CATEGORY(Layer_Shape,_("Internal"));
64 SYNFIG_LAYER_SET_VERSION(Layer_Shape,"0.1");
65 SYNFIG_LAYER_SET_CVS_ID(Layer_Shape,"$Id$");
66
67 #define EPSILON 1e-12
68
69 template < class T >
70 inline bool IsZero(const T &n)
71 {
72         return (n < EPSILON) && (n > -EPSILON);
73 }
74
75 /* === C L A S S E S ======================================================= */
76
77 //Assumes 64 byte aligned structures if at all
78 struct Primitive
79 {
80         int             operation;
81         int             number;
82
83         //Point data[0];
84
85         enum Operations
86         {
87                 NONE = -1,
88                 MOVE_TO = 0,            //(x,y)+                                after first point treated as line_to
89                 CLOSE,                          //                                              NOT RUNLENGTH enabled
90                 LINE_TO,                        //(x,y)+                                continuous func
91                 CONIC_TO,                       //(x1,y1,x,y)+                  "   "
92                 CONIC_TO_SMOOTH,        //(x,y)+                                "   "
93                 CUBIC_TO,                       //(x1,y1,x2,y2,x,y)+    "   "
94                 CUBIC_TO_SMOOTH,        //(x2,y2,x,y)+                  "   "
95                 END
96         };
97 };
98
99 //******** CURVE FUNCTIONS *****************
100 const int       MAX_SUBDIVISION_SIZE = 64;
101 const int       MIN_SUBDIVISION_DRAW_LEVELS = 4;
102
103 static void Subd_Conic_Stack(Point *arc)
104 {
105         /*
106
107         b0
108         *               0+1 a
109         b1 b    *               1+2*1+2 a
110         *               1+2     b       *
111         b2              *
112         *
113
114         0.1.2 ->        0.1 2 3.4
115
116         */
117
118         Real a,b;
119
120
121         arc[4][0] = arc[2][0];
122         b = arc[1][0];
123
124         a = arc[1][0] = (arc[0][0] + b)/2;
125         b = arc[3][0] = (arc[4][0] + b)/2;
126         arc[2][0] = (a + b)/2;
127
128
129         arc[4][1] = arc[2][1];
130         b = arc[1][1];
131
132         a = arc[1][1] = (arc[0][1] + b)/2;
133         b = arc[3][1] = (arc[4][1] + b)/2;
134         arc[2][1] = (a + b)/2;
135
136         /* //USING SIMD
137
138         arc[4] = arc[2];
139
140         arc[3] = (arc[2] + arc[1])/2;
141         arc[1] = (arc[0] + arc[1])/2;
142
143         arc[2] = (arc[1] + arc[3])/2;
144
145         */
146
147 }
148
149 static void Subd_Cubic_Stack(Point *arc)
150 {
151         Real a,b,c;
152
153         /*
154
155         b0
156         *               0+1 a
157         b1 b    *               1+2*1+2 a
158         *               1+2     b       *                       0+3*1+3*2+3
159         b2 c    *               1+2*2+2 b       *
160         *               2+3     c       *
161         b3              *
162         *
163
164         0.1 2.3 ->      0.1 2 3 4 5.6
165
166         */
167
168         arc[6][0] = arc[3][0];
169
170         b = arc[1][0];
171         c = arc[2][0];
172
173         a = arc[1][0] = (arc[0][0] + b)/2;
174         b = (b + c)/2;
175         c = arc[5][0] = (arc[6][0] + c)/2;
176
177         a = arc[2][0] = (a + b)/2;
178         b = arc[4][0] = (b + c)/2;
179
180         arc[3][0] = (a + b)/2;
181
182
183         arc[6][1] = arc[3][1];
184
185         b = arc[1][1];
186         c = arc[2][1];
187
188         a = arc[1][1] = (arc[0][1] + b)/2;
189         b = (b + c)/2;
190         c = arc[5][1] = (arc[6][1] + c)/2;
191
192         a = arc[2][1] = (a + b)/2;
193         b = arc[4][1] = (b + c)/2;
194
195         arc[3][1] = (a + b)/2;
196
197         /* //USING SIMD
198         temp
199
200         arc[6] = arc[3];
201
202         //backwards to avoid overwriting
203         arc[5] = (arc[2] + arc[3])/2;
204         temp = (arc[1] + arc[2])/2;
205         arc[1] = (arc[0] + arc[1])/2;
206
207         arc[4] = (temp + arc[5])/2;
208         arc[2] = (arc[1] + temp)/2;
209
210         arc[3] = (arc[2] + arc[4])/2;
211
212         */
213 }
214
215 //************** PARAMETRIC RENDERER SUPPORT STRUCTURES ****************
216
217 // super segment
218 struct MonoSegment
219 {
220         Rect    aabb;
221         int             ydir;
222         vector<Point>   pointlist;
223
224         MonoSegment(int dir = 0, Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
225         {
226                 aabb.minx = x0;
227                 aabb.maxx = x1;
228                 aabb.miny = y0;
229                 aabb.maxy = y1;
230
231                 ydir = dir;
232         }
233
234         int intersect(Real x,Real y) const
235         {
236                 if((y < aabb.miny) | (y > aabb.maxy) | (x < aabb.minx)) return 0;
237                 if(x > aabb.maxx) return ydir;
238
239                 //int i = 0;
240                 //int size = pointlist.size();
241                 //vector<Point>::const_iterator end = pointlist.end();
242                 vector<Point>::const_iterator p = pointlist.begin();
243
244                 //assumes that the rect culled away anything that would be beyond the edges
245                 if(ydir > 0)
246                 {
247                         while(y > (*++p)[1]);
248                 }
249                 else
250                 {
251                         while(y < (*++p)[1]);
252                 }
253
254                 //for the loop to break there must have been a slope (straight line would do nothing)
255                 //vector<Point>::const_iterator p1 = p-1;
256                 Real dy = p[-1][1] - p[0][1];
257                 Real dx = p[-1][0] - p[0][0];
258
259                 assert(dy != 0);
260
261                 Real xi = p[0][0] + (y - p[0][1]) * dx / dy;
262                 return (x > xi)*ydir;
263         }
264 };
265
266 struct CurveArray
267 {
268         Rect    aabb;   //not necessarily as effective - can only reject values
269         vector<Point>   pointlist;      //run length - p0, p1, p2, p3 = p10, p11, p12, p13 = p20 ...
270         vector<char>    degrees;
271
272         CurveArray(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
273         {
274                 aabb.set(x0,y0,x1,y1);
275         }
276
277         void reset(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
278         {
279                 aabb.set(x0,y0,x1,y1);
280                 pointlist.clear();
281                 degrees.clear();
282         }
283
284         int size () const
285         {
286                 return degrees.size();
287         }
288
289         void Start(Point m)
290         {
291                 reset(m[0],m[0],m[1],m[1]);
292                 pointlist.push_back(m);
293         }
294
295         void AddCubic(Point p1, Point p2, Point dest)
296         {
297                 aabb.expand(p1[0],p1[1]);
298                 aabb.expand(p2[0],p2[1]);
299                 aabb.expand(dest[0],dest[1]);
300
301                 pointlist.push_back(p1);
302                 pointlist.push_back(p2);
303                 pointlist.push_back(dest);
304
305                 degrees.push_back(3);
306         }
307
308         void AddConic(Point p1, Point dest)
309         {
310                 aabb.expand(p1[0],p1[1]);
311                 aabb.expand(dest[0],dest[1]);
312
313                 pointlist.push_back(p1);
314                 pointlist.push_back(dest);
315
316                 degrees.push_back(2);
317         }
318
319         static int intersect_conic(Real x, Real y, Point *p, int level = 0)
320         {
321                 Real ymin,ymax,xmin,xmax;
322                 int intersects = 0;
323
324                 //sort the overall curve ys - degenerate detection
325                 ymin = min(p[0][1],p[2][1]);
326                 ymax = max(p[0][1],p[2][1]);
327
328                 xmin = min(min(p[0][0],p[1][0]),p[2][0]);
329                 xmax = max(max(p[0][0],p[1][0]),p[2][0]);
330
331                 //to the left, to the right and out of range y, or completely out of range y
332                 if( x < xmin ) return 0;
333                 if( x > xmax  & (y > ymax | y < ymin) ) return 0;
334                 if( (y > ymax & y > p[1][1]) | (y < ymin & y < p[1][1]) ) return 0;
335
336                 //degenerate line max
337                 if(ymin == ymax == p[1][1])
338                         return 0;
339
340                 //degenerate accept - to the right and crossing the base line
341                 if(x > xmax)
342                 {
343                         return (y <= ymax & y >= ymin);
344                 }
345
346                 //solve for curve = y
347
348                 //real roots:
349                 //0 roots       - 0 intersection
350                 //1 root        - get x, and figure out x
351                 //2 roots (non-double root)     - get 2 xs, and count xs to the left
352
353                 //for conic we can assume 1 intersection for monotonic curve
354                 Real    a = p[2][1] -   2*p[1][1] +     p[0][1],
355                                 b =                     2*p[1][1] -     2*p[0][1],
356                                 c =                                                     p[0][1]         -       y;
357
358                 Real t1 = -1, t2 = -1;
359
360                 if(a == 0)
361                 {
362                         //linear - easier :)
363                         if(b == 0) return 0; //may not need this check
364
365                         t1 = - c / b; //bt + c = 0 solved
366                 }else
367                 {
368                         //2 degree polynomial
369                         Real b2_4ac = b*b - 4*a*c;
370
371                         //if there are double/no roots - no intersections (in real #s that is)
372                         if(b2_4ac <= 0)
373                         {
374                                 return 0;
375                         }
376
377                         b2_4ac = sqrt(b2_4ac);
378
379                         t1 = (-b - b2_4ac) / 2*a,
380                         t2 = (-b + b2_4ac) / 2*a;
381                 }
382
383                 //calculate number of intersections
384                 if(t1 >= 0 & t1 <= 1)
385                 {
386                         const Real t = t1;
387                         const Real invt = 1 - t;
388
389                         //find x val and it counts if it's to the left of the point
390                         const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0];
391                         const Real dy_t = 2*a*t + b;
392
393                         if(dy_t)
394                         {
395                                 intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
396                         }
397                 }
398
399                 if(t2 >= 0 & t2 <= 1)
400                 {
401                         const Real t = t2;
402                         const Real invt = 1 - t;
403
404                         //find x val and it counts if it's to the left of the point
405                         const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0];
406                         const Real dy_t = 2*a*t + b;
407
408                         if(dy_t)
409                         {
410                                 intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
411                         }
412                 }
413
414                 return intersects;
415         }
416
417         static int      quadratic_eqn(Real a, Real b, Real c, Real *t0, Real *t1)
418         {
419                 const Real b2_4ac = b*b - 4*a*c;
420
421                 //degenerate reject (can't take sqrt)
422                 if(b2_4ac < 0)
423                 {
424                         return 0;
425                 }
426
427                 const Real sqrtb2_4ac = sqrt(b2_4ac);
428                 const Real signb = b < 0 ? -1 : 1;
429                 const Real q = - 0.5 * (b + signb * sqrtb2_4ac);
430
431                 *t0 = q/a;
432                 *t1 = c/q;
433
434                 return sqrtb2_4ac == 0 ? 1 : 2;
435         }
436
437         //Newton-Raphson root polishing (we don't care about bounds, assumes very near the desired root)
438         static Real polish_cubicroot(Real a, Real b, Real c, Real d, Real t, Real *dpdt)
439         {
440                 const Real cn[4] = {a,b,c,d};
441                 Real p,dp,newt,oldpmag=FLT_MAX;
442
443                 //eval cubic eqn and it's derivative
444                 for(;;)
445                 {
446                         p = cn[0]*t + cn[1];
447                         dp = cn[0];
448
449                         for(int i = 2; i < 4; i++)
450                         {
451                                 dp = p + dp*t;
452                                 p = cn[i] + p*t;
453                         }
454
455                         if(dp == 0)
456                         {
457                                 synfig::warning("polish_cubicroot: Derivative should not vanish!!!");
458                                 return t;
459                         }
460
461                         newt = t - p/dp;
462
463                         if(newt == t || fabs(p) >= oldpmag)
464                         {
465                                 *dpdt = dp;
466                                 return t;
467                         }
468
469                         t = newt;
470                         oldpmag = fabs(p);
471                 }
472         }
473
474         static int intersect_cubic(Real x, Real y, Point *p, int level = 0)
475         {
476                 const Real INVALIDROOT = -FLT_MAX;
477                 Real ymin,ymax,xmin,xmax;
478                 Real ymin2,ymax2,ymintot,ymaxtot;
479                 int intersects = 0;
480
481                 //sort the overall curve ys and xs - degenerate detection
482
483                 //open span for the two end points
484                 ymin = min(p[0][1],p[3][1]);
485                 ymax = max(p[0][1],p[3][1]);
486
487                 //other points etc.
488                 ymin2 = min(p[1][1],p[2][1]);
489                 ymax2 = max(p[1][1],p[2][1]);
490
491                 ymintot = min(ymin,ymin2);
492                 ymaxtot = max(ymax,ymax2);
493
494                 //the entire curve control polygon is in this x range
495                 xmin = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0]));
496                 xmax = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][0]));
497
498                 //outside all y boundaries (no intersect)
499                 if( (y > ymaxtot) || (y < ymintot) ) return 0;
500
501                 //left of curve (no intersect)
502                 if(x < xmin) return 0;
503
504                 //right of curve (and outside base range)
505                 if( x > xmax )
506                 {
507                         if( (y > ymax) | (y < ymin) ) return 0;
508
509                         //degenerate accept - to the right and inside the [ymin,ymax] range (already rejected if out of range)
510                         const Real n = p[3][1] - p[0][1];
511
512                         //extract the sign from the value (we need valid data)
513                         return n < 0 ? -1 : 1;
514                 }
515
516                 //degenerate horizontal line max -- doesn't happen enough to check for
517                 if( ymintot == ymaxtot ) return 0;
518
519                 //calculate roots:
520                 // can have 0,1,2, or 3 real roots
521                 // if any of them are double then reject the two...
522
523                 // y-coefficients for f_y(t) - y = 0
524                 Real    a = p[3][1]     - 3*p[2][1]     + 3*p[1][1]     -   p[0][1],
525                                 b =                       3*p[2][1]     - 6*p[1][1]     + 3*p[0][1],
526                                 c =                                                       3*p[1][1]     - 3*p[0][1],
527                                 d =                                                                             p[0][1] - y;
528
529                 Real    ax = p[3][0]    - 3*p[2][0]     + 3*p[1][0]     -   p[0][0],
530                                 bx =                      3*p[2][0]     - 6*p[1][0]     + 3*p[0][0],
531                                 cx =                                              3*p[1][0]     - 3*p[0][0],
532                                 dx =                                                                            p[0][0];
533
534                 Real t1 = INVALIDROOT, t2 = INVALIDROOT, t3 = INVALIDROOT, t, dydt;
535
536                 if(a == 0)
537                 {
538                         //only 2nd degree
539                         if(b == 0)
540                         {
541                                 //linear
542                                 if(c == 0) return 0;
543
544                                 t1 = - d / c; //equation devolved into: ct + d = 0 - solve...
545                         }else
546                         {
547                                 //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective)
548                                 if(quadratic_eqn(a,b,c,&t1,&t2) != 2) return 0;
549                         }
550                 }else
551                 {
552                         //cubic - sigh....
553
554                         //algorithm courtesy of Numerical Recipes in C (algorithm copied from pg. 184/185)
555                         Real an = b / a,
556                                  bn = c / a,
557                                  cn = d / a;
558
559                         //if cn is 0 (or really really close), then we can simplify this...
560                         if(IsZero(cn))
561                         {
562                                 t3 = 0;
563
564                                 //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective)
565                                 if(quadratic_eqn(a,b,c,&t1,&t2) != 2)
566                                 {
567                                         t1 = t2 = INVALIDROOT;
568                                 }
569                         }
570                         else
571                         {
572                                 //otherwise run the normal cubic root equation
573                                 Real Q = (an*an - 3.0*bn) / 9.0;
574                                 Real R = ((2.0*an*an - 9.0*bn)*an + 27.0*cn)/54.0;
575
576                                 if(R*R < Q*Q*Q)
577                                 {
578                                         Real theta = acos(R / sqrt(Q*Q*Q));
579
580                                         t1 = -2.0*sqrt(Q)*cos(theta/3) - an/3.0;
581                                         t2 = -2.0*sqrt(Q)*cos((theta+2*PI)/3.0) - an/3.0;
582                                         t3 = -2.0*sqrt(Q)*cos((theta-2*PI)/3.0) - an/3.0;
583
584                                         //don't need to reorder,l just need to eliminate double/triple roots
585                                         //if(t3 == t2 & t1 == t2) t2 = t3 = INVALIDROOT;
586                                         if(t3 == t2) t2 = t3 = INVALIDROOT;
587                                         if(t1 == t2) t1 = t2 = INVALIDROOT;
588                                         if(t1 == t3) t1 = t3 = INVALIDROOT;
589                                 }else
590                                 {
591                                         Real signR = R < 0 ? -1 : 1;
592                                         Real A = - signR * pow(signR*R + sqrt(R*R - Q*Q*Q),1/3.0);
593
594                                         Real B;
595                                         if(A == 0) B = 0;
596                                         else B = Q / A;
597
598                                         //single real root in this case
599                                         t1 = (A + B) - an/3.0;
600                                 }
601                         }
602                 }
603
604                 //if(t1 != INVALIDROOT)
605                 {
606                         t = t1;//polish_cubicroot(a,b,c,d,t1,&dydt);
607                         if(t >= 0 & t < 1)
608                         {
609                                 //const Real invt = 1 - t;
610
611                                 //find x val and it counts if it's to the left of the point
612                                 const Real xi = ((ax*t + bx)*t + cx)*t + dx;
613                                 dydt = (3*a*t + 2*b)*t + c;
614
615                                 if(dydt)
616                                 {
617                                         intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
618                                 }
619                         }
620                 }
621
622                 //if(t2 != INVALIDROOT)
623                 {
624                         t = t2;//polish_cubicroot(a,b,c,d,t2,&dydt);
625                         if(t >= 0 & t < 1)
626                         {
627                                 //const Real invt = 1 - t;
628
629                                 //find x val and it counts if it's to the left of the point
630                                 const Real xi = ((ax*t + bx)*t + cx)*t + dx;
631                                 dydt = (3*a*t + 2*b)*t + c;
632
633                                 if(dydt)
634                                 {
635                                         intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
636                                 }
637                         }
638                 }
639
640                 //if(t3 != INVALIDROOT)
641                 {
642                         t = t3;//polish_cubicroot(a,b,c,d,t3,&dydt);
643                         if(t >= 0 & t < 1)
644                         {
645                                 //const Real invt = 1 - t;
646
647                                 //find x val and it counts if it's to the left of the point
648                                 const Real xi = ((ax*t + bx)*t + cx)*t + dx;
649                                 dydt = (3*a*t + 2*b)*t + c;
650
651                                 if(dydt)
652                                 {
653                                         intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
654                                 }
655                         }
656                 }
657
658                 return intersects;
659         }
660
661         int intersect(Real x,Real y, Point *table) const
662         {
663                 if((y < aabb.miny) | (y > aabb.maxy) | (x < aabb.minx)) return 0;
664
665                 int i, curdeg, intersects = 0;
666                 const int numcurves = degrees.size();
667
668                 vector<Point>::const_iterator   p = pointlist.begin();
669
670                 for(i=0; i < numcurves; i++)
671                 {
672                         curdeg = degrees[i];
673
674                         switch(curdeg)
675                         {
676                                 case 2:
677                                 {
678                                         table[0] = *p++;
679                                         table[1] = *p++;
680                                         table[2] = *p;  //we want to include the last point for the next curve
681
682                                         intersects += intersect_conic(x,y,table);
683
684                                         break;
685                                 }
686
687                                 case 3:
688                                 {
689                                         table[0] = *p++;
690                                         table[1] = *p++;
691                                         table[2] = *p++;
692                                         table[3] = *p;  //we want to include the last point for the next curve
693
694                                         intersects += intersect_cubic(x,y,table);
695
696                                         break;
697                                 }
698
699                                 default:
700                                 {
701                                         warning("Invalid degree (%d) inserted into the list (index: %d)\n", curdeg, i);
702                                         return 0;
703                                 }
704                         }
705                 }
706
707                 return intersects;
708         }
709 };
710
711 struct Layer_Shape::Intersector
712 {
713         Rect    aabb;
714
715         //! true iff aabb hasn't been initialised yet
716         bool    initaabb;
717
718         int     flags;
719
720         enum IntersectorFlags
721         {
722                 NotClosed = 0x8000
723         };
724
725         enum PrimitiveType
726         {
727                 TYPE_NONE = 0,
728                 TYPE_LINE,
729                 TYPE_CURVE
730         };
731
732         Real    cur_x,cur_y;
733         Real    close_x,close_y;
734
735         vector<MonoSegment>                             segs;   //monotonically increasing
736         vector<CurveArray>                              curves; //big array of consecutive curves
737
738         int                                                             prim;
739         Vector                                                  tangent;
740
741         Intersector()
742         {
743                 clear();
744         }
745
746         bool notclosed()
747         {
748                 return (flags & NotClosed) | (cur_x != close_x) | (cur_y != close_y);
749         }
750
751         void move_to(Real x, Real y)
752         {
753                 close();
754
755                 close_x = cur_x = x;
756                 close_y = cur_y = y;
757
758                 tangent[0] = tangent[1] = 0;
759
760                 if(initaabb)
761                 {
762                         aabb.set_point(x,y);
763                         initaabb = false;
764                 }else aabb.expand(x,y);
765
766                 prim = TYPE_NONE;
767         }
768
769         void line_to(Real x, Real y)
770         {
771                 int dir = (y > cur_y)*1 + (-1)*(y < cur_y);
772
773                 //check for context (if not line start a new segment)
774                 //if we're not in line mode (covers 0 set case), or if directions are different (not valid for 0 direction)
775                 if(prim != TYPE_LINE || (dir && segs.back().ydir != dir))
776                 {
777                         MonoSegment             seg(dir,x,x,y,y);
778
779                         seg.aabb.expand(cur_x,cur_y);
780                         seg.pointlist.push_back(Point(cur_x,cur_y));
781                         seg.pointlist.push_back(Point(x,y));
782                         segs.push_back(seg);
783                 }
784                 //add to the last segment, because it works
785                 else
786                 {
787                         segs.back().pointlist.push_back(Point(x,y));
788                         segs.back().aabb.expand(x,y);
789                 }
790
791
792
793                 cur_x = x;
794                 cur_y = y;
795                 aabb.expand(x,y); //expand the entire thing's bounding box
796
797                 tangent[0] = x - cur_x;
798                 tangent[1] = x - cur_y;
799
800                 flags |= NotClosed;
801                 prim = TYPE_LINE;
802         }
803
804         void conic_to_smooth(Real x, Real y)
805         {
806                 const Real x1 = tangent[0]/2.0 + cur_x;
807                 const Real y1 = tangent[1]/2.0 + cur_y;
808
809                 conic_to(x1,y1,x,y);
810         }
811
812         void conic_to(Real x1, Real y1, Real x, Real y)
813         {
814                 //if we're not already a curve start one
815                 if(prim != TYPE_CURVE)
816                 {
817                         CurveArray      c;
818
819                         c.Start(Point(cur_x,cur_y));
820                         c.AddConic(Point(x1,y1),Point(x,y));
821
822                         curves.push_back(c);
823                 }else
824                 {
825                         curves.back().AddConic(Point(x1,y1),Point(x,y));
826                 }
827
828                 cur_x = x;
829                 cur_y = y;
830
831                 aabb.expand(x1,y1);
832                 aabb.expand(x,y);
833
834                 tangent[0] = 2*(x - x1);
835                 tangent[1] = 2*(y - y1);
836
837                 flags |= NotClosed;
838                 prim = TYPE_CURVE;
839         }
840
841         void curve_to_smooth(Real x2, Real y2, Real x, Real y)
842         {
843                 Real x1 = tangent[0]/3.0 + cur_x;
844                 Real y1 = tangent[1]/3.0 + cur_y;
845
846                 curve_to(x1,y1,x2,y2,x,y);
847         }
848
849         void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
850         {
851                 //if we're not already a curve start one
852                 if(prim != TYPE_CURVE)
853                 {
854                         CurveArray      c;
855
856                         c.Start(Point(cur_x,cur_y));
857                         c.AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
858
859                         curves.push_back(c);
860                 }else
861                 {
862                         curves.back().AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
863                 }
864
865                 cur_x = x;
866                 cur_y = y;
867
868                 //expand bounding box around ALL of it
869                 aabb.expand(x1,y1);
870                 aabb.expand(x2,y2);
871                 aabb.expand(x,y);
872
873                 tangent[0] = 3*(x - x2);
874                 tangent[1] = 3*(y - y2);
875
876                 flags |= NotClosed;
877                 prim = TYPE_CURVE;
878         }
879
880         void close()
881         {
882                 if(flags & NotClosed)
883                 {
884                         if(cur_x != close_x || cur_y != close_y)
885                         {
886                                 line_to(close_x,close_y);
887                         }
888
889                         flags &= ~NotClosed;
890                 }
891         }
892
893         //assumes the line to count the intersections with is (-1,0)
894         int     intersect (Real x, Real y) const
895         {
896                 int inter = 0;
897                 unsigned int i;
898                 vector<MonoSegment>::const_iterator s = segs.begin();
899                 vector<CurveArray>::const_iterator c = curves.begin();
900
901                 Point   memory[3*MAX_SUBDIVISION_SIZE + 1];
902
903                 for(i = 0; i < segs.size(); i++,s++)
904                 {
905                         inter += s->intersect(x,y);
906                 }
907
908                 for(i=0; i < curves.size(); i++,c++)
909                         inter += c->intersect(x,y,memory);
910
911                 return inter;
912         }
913
914         //intersect an arbitrary line
915         //int   intersect (Real x, Real y, Real vx, Real vy) {return 0;}
916
917         void clear()
918         {
919                 segs.clear();
920                 curves.clear();
921
922                 flags = 0;
923                 cur_x = cur_y = close_x = close_y = 0;
924                 prim = TYPE_NONE;
925                 tangent[0] = tangent[1] = 0;
926                 initaabb = true;
927         }
928 };
929
930 //*********** SCANLINE RENDERER SUPPORT STRUCTURES ***************
931 struct PenMark
932 {
933         int y,x;
934         Real cover,area;
935
936         PenMark(){}
937         PenMark(int xin, int yin, Real c, Real a)
938                 :y(yin),x(xin),cover(c),area(a) {}
939
940         void set(int xin, int yin, Real c, Real a)      { y = yin; x = xin; cover = c; area = a;        }
941
942         void setcoord(int xin, int yin)                         { y = yin; x = xin;     }
943
944         void setcover(Real c, Real a)                           { cover = c; area = a; }
945         void addcover(Real c, Real a)                           { cover += c; area += a; }
946
947         bool operator < (const PenMark &rhs) const
948         {
949                 return y == rhs.y ? x < rhs.x : y < rhs.y;
950         }
951 };
952
953 typedef rect<int> ContextRect;
954
955 class Layer_Shape::PolySpan
956 {
957 public:
958         typedef deque<PenMark>  cover_array;
959
960         Point                   arc[3*MAX_SUBDIVISION_SIZE + 1];
961
962         cover_array             covers;
963         PenMark                 current;
964
965         int                             open_index;
966
967         //ending position of last primitive
968         Real                    cur_x;
969         Real                    cur_y;
970
971         //starting position of current primitive list
972         Real                    close_x;
973         Real                    close_y;
974
975         //flags for the current segment
976         int                             flags;
977
978         //the window that will be drawn (used for clipping)
979         ContextRect             window;
980
981         //for assignment to flags value
982         enum PolySpanFlags
983         {
984                 NotSorted = 0x8000,
985                 NotClosed =     0x4000
986         };
987
988         //default constructor - 0 everything
989         PolySpan() :current(0,0,0,0),flags(NotSorted)
990         {
991                 cur_x = cur_y = close_x = close_y = 0;
992                 open_index = 0;
993         }
994
995         bool notclosed() const
996         {
997                 return (flags & NotClosed) | (cur_x != close_x) | (cur_y != close_y);
998         }
999
1000         //0 out all the variables involved in processing
1001         void clear()
1002         {
1003                 covers.clear();
1004                 cur_x = cur_y = close_x = close_y = 0;
1005                 open_index = 0;
1006                 current.set(0,0,0,0);
1007                 flags = NotSorted;
1008         }
1009
1010         //add the current cell, but only if there is information to add
1011         void addcurrent()
1012         {
1013                 if(current.cover || current.area)
1014                 {
1015                         covers.push_back(current);
1016                 }
1017         }
1018
1019         //move to the next cell (cover values 0 initially), keeping the current if necessary
1020         void move_pen(int x, int y)
1021         {
1022                 if(y != current.y | x != current.x)
1023                 {
1024                         addcurrent();
1025                         current.set(x,y,0,0);
1026                 }
1027         }
1028
1029         //close the primitives with a line (or rendering will not work as expected)
1030         void close()
1031         {
1032                 if(flags & NotClosed)
1033                 {
1034                         if(cur_x != close_x || cur_y != close_y)
1035                         {
1036                                 line_to(close_x,close_y);
1037                                 addcurrent();
1038                                 current.setcover(0,0);
1039                         }
1040                         flags &= ~NotClosed;
1041                 }
1042         }
1043
1044         // Not recommended - destroys any separation of spans currently held
1045         void merge_all()
1046         {
1047                 sort(covers.begin(),covers.end());
1048                 open_index = 0;
1049         }
1050
1051         //will sort the marks if they are not sorted
1052         void sort_marks()
1053         {
1054                 if(flags & NotSorted)
1055                 {
1056                         //only sort the open index
1057                         addcurrent();
1058                         current.setcover(0,0);
1059
1060                         sort(covers.begin() + open_index,covers.end());
1061                         flags &= ~NotSorted;
1062                 }
1063         }
1064
1065         //encapsulate the current sublist of marks (used for drawing)
1066         void encapsulate_current()
1067         {
1068                 //sort the current list then reposition the open list section
1069                 sort_marks();
1070                 open_index = covers.size();
1071         }
1072
1073         //move to start a new primitive list (enclose the last primitive if need be)
1074         void move_to(Real x, Real y)
1075         {
1076                 close();
1077                 if(isnan(x))x=0;
1078                 if(isnan(y))y=0;
1079                 move_pen((int)floor(x),(int)floor(y));
1080                 close_y = cur_y = y;
1081                 close_x = cur_x = x;
1082         }
1083
1084         //primitive_to functions
1085         void line_to(Real x, Real y);
1086         void conic_to(Real x1, Real y1, Real x, Real y);
1087         void cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y);
1088
1089         void draw_scanline(int y, Real x1, Real y1, Real x2, Real y2);
1090         void draw_line(Real x1, Real y1, Real x2, Real y2);
1091
1092         Real ExtractAlpha(Real area)
1093         {
1094                 //non-zero winding style
1095                 if(area < 0) area = -area;
1096                 if(area > 1) area = 1;
1097
1098                 //even-odd winding style
1099                 /*if(area < 0) area = -area;
1100
1101                 while(area > 2) area -= 2;
1102                 if(area > 1) area = 1-area; //want pyramid like thing
1103                 */
1104                 //broken? - yep broken
1105
1106                 return area;
1107         }
1108 };
1109
1110 /* === M E T H O D S ======================================================= */
1111
1112 Layer_Shape::Layer_Shape(const Real &a, const Color::BlendMethod m):
1113         Layer_Composite (a,m),
1114         edge_table              (new Intersector),
1115         color                   (Color::black()),
1116         offset                  (0,0),
1117         invert                  (false),
1118         antialias               (true),
1119         blurtype                (Blur::FASTGAUSSIAN),
1120         feather                 (0),
1121         bytestream              (0),
1122         lastbyteop              (Primitive::NONE),
1123         lastoppos               (-1)
1124 {
1125 }
1126
1127 Layer_Shape::~Layer_Shape()
1128 {
1129         delete edge_table;
1130 }
1131
1132 void
1133 Layer_Shape::clear()
1134 {
1135         edge_table->clear();
1136         bytestream.clear();
1137 }
1138
1139 bool
1140 Layer_Shape::set_param(const String & param, const ValueBase &value)
1141 {
1142         IMPORT(color);
1143         IMPORT(offset);
1144         IMPORT(invert);
1145         IMPORT(antialias);
1146         IMPORT(feather);
1147         IMPORT(blurtype);
1148
1149         return Layer_Composite::set_param(param,value);
1150 }
1151
1152 ValueBase
1153 Layer_Shape::get_param(const String &param)const
1154 {
1155         EXPORT(color);
1156         EXPORT(offset);
1157         EXPORT(invert);
1158         EXPORT(antialias);
1159         EXPORT(feather);
1160         EXPORT(blurtype);
1161
1162         EXPORT_NAME();
1163         EXPORT_VERSION();
1164
1165         return Layer_Composite::get_param(param);
1166 }
1167
1168 Layer::Vocab
1169 Layer_Shape::get_param_vocab()const
1170 {
1171         Layer::Vocab ret(Layer_Composite::get_param_vocab());
1172
1173         ret.push_back(ParamDesc("color")
1174                 .set_local_name(_("Color"))
1175                 .set_description(_("Layer_Shape Color"))
1176         );
1177         ret.push_back(ParamDesc("offset")
1178                 .set_local_name(_("Position"))
1179         );
1180         ret.push_back(ParamDesc("invert")
1181                 .set_local_name(_("Invert"))
1182         );
1183         ret.push_back(ParamDesc("antialias")
1184                 .set_local_name(_("Antialiasing"))
1185         );
1186         ret.push_back(ParamDesc("feather")
1187                 .set_local_name(_("Feather"))
1188                 .set_is_distance()
1189         );
1190         ret.push_back(ParamDesc("blurtype")
1191                 .set_local_name(_("Type of Feather"))
1192                 .set_description(_("Type of feathering to use"))
1193                 .set_hint("enum")
1194                 .add_enum_value(Blur::BOX,"box",_("Box Blur"))
1195                 .add_enum_value(Blur::FASTGAUSSIAN,"fastgaussian",_("Fast Gaussian Blur"))
1196                 .add_enum_value(Blur::CROSS,"cross",_("Cross-Hatch Blur"))
1197                 .add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
1198                 .add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
1199         );
1200
1201         return ret;
1202 }
1203
1204 synfig::Layer::Handle
1205 Layer_Shape::hit_check(synfig::Context context, const synfig::Point &p)const
1206 {
1207         Point pos(p-offset);
1208
1209         int intercepts = edge_table->intersect(pos[0],pos[1]);
1210
1211         // If we have an odd number of intercepts, we are inside.
1212         // If we have an even number of intercepts, we are outside.
1213         bool intersect = ((!!intercepts) ^ invert);
1214
1215         if(get_amount() == 0 || get_blend_method() == Color::BLEND_ALPHA_OVER)
1216         {
1217                 intersect = false;
1218         }
1219
1220         if(intersect)
1221         {
1222                 synfig::Layer::Handle tmp;
1223                 if(get_blend_method()==Color::BLEND_BEHIND && (tmp=context.hit_check(p)))
1224                         return tmp;
1225                 if(Color::is_onto(get_blend_method()))
1226                 {
1227                         //if there's something in the lower layer then we're set...
1228                         if(!context.hit_check(p).empty())
1229                                 return const_cast<Layer_Shape*>(this);
1230                 }else if(get_blend_method() == Color::BLEND_ALPHA_OVER)
1231                 {
1232                         synfig::info("layer_shape::hit_check - we've got alphaover");
1233                         //if there's something in the lower layer then we're set...
1234                         if(color.get_a() < 0.1 && get_amount() > .9)
1235                         {
1236                                 synfig::info("layer_shape::hit_check - can see through us... so nothing");
1237                                 return Handle();
1238                         }else return context.hit_check(p);
1239                 }else
1240                         return const_cast<Layer_Shape*>(this);
1241         }
1242
1243         return context.hit_check(p);
1244 }
1245
1246 Color
1247 Layer_Shape::get_color(Context context, const Point &p)const
1248 {
1249         Point pp = p;
1250
1251         if(feather)
1252                 pp = Blur(feather,feather,blurtype)(p);
1253
1254         Point pos(pp-offset);
1255
1256         int intercepts = edge_table->intersect(pos[0],pos[1]);
1257
1258         // If we have an odd number of intercepts, we are inside.
1259         // If we have an even number of intercepts, we are outside.
1260         bool intersect = ((!!intercepts) ^ invert);
1261
1262         if(!intersect)
1263                 return context.get_color(pp);
1264
1265         //Ok, we're inside... bummmm ba bum buM...
1266         if(get_blend_method() == Color::BLEND_STRAIGHT && get_amount() == 1)
1267                 return color;
1268         else
1269                 return Color::blend(color,context.get_color(p),get_amount(),get_blend_method());
1270 }
1271
1272 //************** SCANLINE RENDERING *********************
1273 void Layer_Shape::PolySpan::line_to(Real x, Real y)
1274 {
1275         Real n[4];
1276         bool afterx = false;
1277
1278         const Real xin(x), yin(y);
1279
1280         Real dx = x - cur_x;
1281         Real dy = y - cur_y;
1282
1283         //CLIP IT!!!!
1284         try {
1285         //outside y - ignore entirely
1286         if(      (cur_y >= window.maxy & y >= window.maxy)
1287                 |(cur_y <  window.miny & y <  window.miny) )
1288         {
1289                 cur_x = x;
1290                 cur_y = y;
1291         }
1292         else //not degenerate - more complicated
1293         {
1294                 if(dy > 0) //be sure it's not tooooo small
1295                 {
1296                         // cur_y ... window.miny ... window.maxy ... y
1297
1298                         //initial degenerate - initial clip
1299                         if(cur_y < window.miny)
1300                         {
1301                                 //new clipped start point (must also move pen)
1302                                 n[2] = cur_x + (window.miny - cur_y) * dx / dy;
1303
1304                                 cur_x = n[2];
1305                                 cur_y = window.miny;
1306                                 move_pen((int)floor(cur_x),window.miny);
1307                         }
1308
1309                         //generate data for the ending clipped info
1310                         if(y > window.maxy)
1311                         {
1312                                 //intial line to intersection (and degenerate)
1313                                 n[2] = x + (window.maxy - y) * dx / dy;
1314
1315                                 //intersect coords
1316                                 x = n[2];
1317                                 y = window.maxy;
1318                         }
1319                 }
1320                 else
1321                 {
1322                         //initial degenerate - initial clip
1323                         if(cur_y > window.maxy)
1324                         {
1325                                 //new clipped start point (must also move pen)
1326                                 n[2] = cur_x + (window.maxy - cur_y) * dx / dy;
1327
1328                                 cur_x = n[2];
1329                                 cur_y = window.maxy;
1330                                 move_pen((int)floor(cur_x),window.maxy);
1331                         }
1332
1333                         //generate data for the ending clipped info
1334                         if(y < window.miny)
1335                         {
1336                                 //intial line to intersection (and degenerate)
1337                                 n[2] = x + (window.miny - y) * dx / dy;
1338
1339                                 //intersect coords
1340                                 x = n[2];
1341                                 y = window.miny;
1342                         }
1343                 }
1344
1345                 //all degenerate - but require bounded clipped values
1346                 if(   (cur_x >= window.maxx && x >= window.maxx)
1347                         ||(cur_x <  window.minx && x <  window.minx) )
1348                 {
1349                         //clip both vertices - but only needed in the x direction
1350                         cur_x = max(cur_x,      (Real)window.minx);
1351                         cur_x = min(cur_x,      (Real)window.maxx);
1352
1353                         //clip the dest values - y is already clipped
1354                         x = max(x,(Real)window.minx);
1355                         x = min(x,(Real)window.maxx);
1356
1357                         //must start at new point...
1358                         move_pen((int)floor(cur_x),(int)floor(cur_y));
1359
1360                         draw_line(cur_x,cur_y,x,y);
1361
1362                         cur_x = xin;
1363                         cur_y = yin;
1364                 }
1365                 else
1366                 {
1367                         //clip x
1368                         if(dx > 0)
1369                         {
1370                                 //initial degenerate - initial clip
1371                                 if(cur_x < window.minx)
1372                                 {
1373                                         //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
1374                                         n[2] = cur_y + (window.minx - cur_x) * dy / dx;
1375
1376                                         move_pen(window.minx,(int)floor(cur_y));
1377                                         draw_line(window.minx,cur_y,window.minx,n[2]);
1378
1379                                         cur_x = window.minx;
1380                                         cur_y = n[2];
1381                                 }
1382
1383                                 //generate data for the ending clipped info
1384                                 if(x > window.maxx)
1385                                 {
1386                                         //intial line to intersection (and degenerate)
1387                                         n[2] = y + (window.maxx - x) * dy / dx;
1388
1389                                         n[0] = window.maxx;
1390                                         n[1] = y;
1391
1392                                         //intersect coords
1393                                         x = window.maxx;
1394                                         y = n[2];
1395                                         afterx = true;
1396                                 }
1397                         }else
1398                         {
1399                                 //initial degenerate - initial clip
1400                                 if(cur_x > window.maxx)
1401                                 {
1402                                         //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
1403                                         n[2] = cur_y + (window.maxx - cur_x) * dy / dx;
1404
1405                                         move_pen(window.maxx,(int)floor(cur_y));
1406                                         draw_line(window.maxx,cur_y,window.maxx,n[2]);
1407
1408                                         cur_x = window.maxx;
1409                                         cur_y = n[2];
1410                                 }
1411
1412                                 //generate data for the ending clipped info
1413                                 if(x < window.minx)
1414                                 {
1415                                         //intial line to intersection (and degenerate)
1416                                         n[2] = y + (window.minx - x) * dy / dx;
1417
1418                                         n[0] = window.minx;
1419                                         n[1] = y;
1420
1421                                         //intersect coords
1422                                         x = window.minx;
1423                                         y = n[2];
1424                                         afterx = true;
1425                                 }
1426                         }
1427
1428                         move_pen((int)floor(cur_x),(int)floor(cur_y));
1429                         //draw the relevant line (clipped)
1430                         draw_line(cur_x,cur_y,x,y);
1431
1432                         if(afterx)
1433                         {
1434                                 draw_line(x,y,n[0],n[1]);
1435                         }
1436
1437                         cur_x = xin;
1438                         cur_y = yin;
1439                 }
1440         }
1441         } catch(...) { synfig::error("line_to: cur_x=%f, cur_y=%f, x=%f, y=%f", cur_x, cur_y, x, y); throw; }
1442
1443         flags |= NotClosed|NotSorted;
1444 }
1445
1446 static inline bool clip_conic(const Point *const p, const ContextRect &r)
1447 {
1448         const Real minx = min(min(p[0][0],p[1][0]),p[2][0]);
1449         const Real miny = min(min(p[0][1],p[1][1]),p[2][1]);
1450         const Real maxx = max(max(p[0][0],p[1][0]),p[2][0]);
1451         const Real maxy = max(max(p[0][1],p[1][1]),p[2][1]);
1452
1453         return  (minx > r.maxx) |
1454                         (maxx < r.minx) |
1455                         (miny > r.maxy) |
1456                         (maxy < r.miny);
1457 }
1458
1459 static inline bool clip_cubic(const Point *const p, const ContextRect &r)
1460 {
1461         /*const Real minx = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0]));
1462         const Real miny = min(min(p[0][1],p[1][1]),min(p[2][1],p[3][1]));
1463         const Real maxx = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][1]));
1464         const Real maxy = max(max(p[0][1],p[1][1]),max(p[2][1],p[3][1]));
1465
1466         return  (minx > r.maxx) ||
1467                         (maxx < r.minx) ||
1468                         (miny > r.maxy) ||
1469                         (maxy < r.miny);*/
1470
1471         return  ((p[0][0] > r.maxx) & (p[1][0] > r.maxx) & (p[2][0] > r.maxx) & (p[3][0] > r.maxx)) |
1472                         ((p[0][0] < r.minx) & (p[1][0] < r.minx) & (p[2][0] < r.minx) & (p[3][0] < r.minx)) |
1473                         ((p[0][1] > r.maxy) & (p[1][1] > r.maxy) & (p[2][1] > r.maxy) & (p[3][1] > r.maxy)) |
1474                         ((p[0][1] < r.miny) & (p[1][1] < r.miny) & (p[2][1] < r.miny) & (p[3][1] < r.miny));
1475 }
1476
1477 static inline Real max_edges_cubic(const Point *const p)
1478 {
1479         const Real x1 = p[1][0] - p[0][0];
1480         const Real y1 = p[1][1] - p[0][1];
1481
1482         const Real x2 = p[2][0] - p[1][0];
1483         const Real y2 = p[2][1] - p[1][1];
1484
1485         const Real x3 = p[3][0] - p[2][0];
1486         const Real y3 = p[3][1] - p[2][1];
1487
1488         const Real d1 = x1*x1 + y1*y1;
1489         const Real d2 = x2*x2 + y2*y2;
1490         const Real d3 = x3*x3 + y3*y3;
1491
1492         return max(max(d1,d2),d3);
1493 }
1494
1495 static inline Real max_edges_conic(const Point *const p)
1496 {
1497         const Real x1 = p[1][0] - p[0][0];
1498         const Real y1 = p[1][1] - p[0][1];
1499
1500         const Real x2 = p[2][0] - p[1][0];
1501         const Real y2 = p[2][1] - p[1][1];
1502
1503         const Real d1 = x1*x1 + y1*y1;
1504         const Real d2 = x2*x2 + y2*y2;
1505
1506         return max(d1,d2);
1507 }
1508
1509 void Layer_Shape::PolySpan::conic_to(Real x1, Real y1, Real x, Real y)
1510 {
1511         Point *current = arc;
1512         int             level = 0;
1513         int     num = 0;
1514         bool    onsecond = false;
1515
1516         arc[0] = Point(x,y);
1517         arc[1] = Point(x1,y1);
1518         arc[2] = Point(cur_x,cur_y);
1519
1520         //just draw the line if it's outside
1521         if(clip_conic(arc,window))
1522         {
1523                 line_to(x,y);
1524                 return;
1525         }
1526
1527         //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
1528         while(current >= arc)
1529         {
1530                 if(num >= MAX_SUBDIVISION_SIZE)
1531                 {
1532                         warning("Curve subdivision somehow ran out of space while tesselating!");
1533
1534                         //do something...
1535                         assert(0);
1536                         return;
1537                 }else
1538                 //if the curve is clipping then draw degenerate
1539                 if(clip_conic(current,window))
1540                 {
1541                         line_to(current[0][0],current[0][1]); //backwards so front is destination
1542                         current -= 2;
1543                         if(onsecond) level--;
1544                         onsecond = true;
1545                         num--;
1546                         continue;
1547                 }else
1548                 //if we are not at the level minimum
1549                 if(level < MIN_SUBDIVISION_DRAW_LEVELS)
1550                 {
1551                         Subd_Conic_Stack(current);
1552                         current += 2;           //cursor on second curve
1553                         level ++;
1554                         num ++;
1555                         onsecond = false;
1556                         continue;
1557                 }else
1558                 //split it again, if it's too big
1559                 if(max_edges_conic(current) > 0.25) //distance of .5 (cover no more than half the pixel)
1560                 {
1561                         Subd_Conic_Stack(current);
1562                         current += 2;           //cursor on second curve
1563                         level ++;
1564                         num ++;
1565                         onsecond = false;
1566                 }
1567                 else    //NOT TOO BIG? RENDER!!!
1568                 {
1569                         //cur_x,cur_y = current[2], so we need to go 1,0
1570                         line_to(current[1][0],current[1][1]);
1571                         line_to(current[0][0],current[0][1]);
1572
1573                         current -= 2;
1574                         if(onsecond) level--;
1575                         num--;
1576                         onsecond = true;
1577                 }
1578         }
1579 }
1580
1581 void Layer_Shape::PolySpan::cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
1582 {
1583         Point *current = arc;
1584         int             num = 0;
1585         int             level = 0;
1586         bool    onsecond = false;
1587
1588         arc[0] = Point(x,y);
1589         arc[1] = Point(x2,y2);
1590         arc[2] = Point(x1,y1);
1591         arc[3] = Point(cur_x,cur_y);
1592
1593         //just draw the line if it's outside
1594         if(clip_cubic(arc,window))
1595         {
1596                 line_to(x,y);
1597                 return;
1598         }
1599
1600         //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
1601         while(current >= arc) //once current goes below arc, there are no more curves left
1602         {
1603                 if(num >= MAX_SUBDIVISION_SIZE)
1604                 {
1605                         warning("Curve subdivision somehow ran out of space while tesselating!");
1606
1607                         //do something...
1608                         assert(0);
1609                         return;
1610                 }else
1611
1612                 //if we are not at the level minimum
1613                 if(level < MIN_SUBDIVISION_DRAW_LEVELS)
1614                 {
1615                         Subd_Cubic_Stack(current);
1616                         current += 3;           //cursor on second curve
1617                         level ++;
1618                         num ++;
1619                         onsecond = false;
1620                         continue;
1621                 }else
1622                 //if the curve is clipping then draw degenerate
1623                 if(clip_cubic(current,window))
1624                 {
1625                         line_to(current[0][0],current[0][1]); //backwards so front is destination
1626                         current -= 3;
1627                         if(onsecond) level--;
1628                         onsecond = true;
1629                         num --;
1630                         continue;
1631                 }
1632                 else
1633                 //split it again, if it's too big
1634                 if(max_edges_cubic(current) > 0.25) //could use max_edges<3>
1635                 {
1636                         Subd_Cubic_Stack(current);
1637                         current += 3;           //cursor on second curve
1638                         level ++;
1639                         num ++;
1640                         onsecond = false;
1641                 }
1642                 else //NOT TOO BIG? RENDER!!!
1643                 {
1644                         //cur_x,cur_y = current[3], so we need to go 2,1,0
1645                         line_to(current[2][0],current[2][1]);
1646                         line_to(current[1][0],current[1][1]);
1647                         line_to(current[0][0],current[0][1]);
1648
1649                         current -= 3;
1650                         if(onsecond) level--;
1651                         num --;
1652                         onsecond = true;
1653                 }
1654         }
1655 }
1656
1657 //******************** LINE ALGORITHMS ****************************
1658 // THESE CALCULATE THE AREA AND THE COVER FOR THE MARKS, TO THEN SCAN CONVERT
1659 // - BROKEN UP INTO SCANLINES (draw_line - y intersections),
1660 //   THEN THE COVER AND AREA PER TOUCHED PIXEL IS CALCULATED (draw_scanline - x intersections)
1661 void Layer_Shape::PolySpan::draw_scanline(int y, Real x1, Real fy1, Real x2, Real fy2)
1662 {
1663         int     ix1 = (int)floor(x1);
1664         int     ix2 = (int)floor(x2);
1665         Real fx1 = x1 - ix1;
1666         Real fx2 = x2 - ix2;
1667
1668         Real dx,dy,dydx,mult;
1669
1670         dx = x2 - x1;
1671         dy = fy2 - fy1;
1672
1673         //case horizontal line
1674         if(fy1 == fy2)
1675         {
1676                 move_pen(ix2,y); //pen needs to be at the last coord
1677                 return;
1678         }
1679
1680         //case all in same pixel
1681         if(ix1 == ix2)  //impossible for degenerate case (covered by the previous cases)
1682         {
1683                 current.addcover(dy,(fx1 + fx2)*dy/2); //horizontal trapazoid area
1684                 return;
1685         }
1686
1687         if(dx > 0)
1688         {
1689                 // ---->        fx1...1  0...1  ...  0...1  0...fx2
1690                 dydx = dy / dx;
1691
1692                 //set initial values
1693                 //Iterate through the covered pixels
1694                 mult = (1 - fx1)*dydx;  //next y intersection diff value (at 1)
1695
1696                 //first pixel
1697                 current.addcover(mult,(1 + fx1)*mult/2);        // fx1,fy1,1,fy@1 - starting trapazoidal area
1698
1699                 //move to the next pixel
1700                 fy1 += mult;
1701                 ix1++;
1702
1703                 move_pen(ix1,y);
1704
1705                 //set up for whole ones
1706                 while(ix1 != ix2)
1707                 {
1708                         //trapezoid(0,y1,1,y1+dydx);
1709                         current.addcover(dydx,dydx/2);  //accumulated area 1/2 the cover
1710
1711                         //move to next pixel (+1)
1712                         ix1++;
1713                         fy1 += dydx;
1714                         move_pen(ix1,y);
1715                 }
1716
1717                 //last pixel
1718                 //final y-pos - last intersect pos
1719                 mult = fx2 * dydx;
1720                 current.addcover(mult,(0+fx2)*mult/2);
1721         }else
1722         {
1723                 // fx2...1  0...1  ...  0...1  0...fx1   <----
1724                 //mult = (0 - fx1) * dy / dx;
1725                 //neg sign sucked into dydx
1726                 dydx = -dy / dx;
1727
1728                 //set initial values
1729                 //Iterate through the covered pixels
1730                 mult = fx1*dydx;        //next y intersection diff value
1731
1732                 //first pixel
1733                 current.addcover(mult,fx1*mult/2);      // fx1,fy1,0,fy@0 - starting trapazoidal area
1734
1735                 //move to next pixel
1736                 fy1 += mult;
1737                 ix1--;
1738
1739                 move_pen(ix1,y);
1740
1741                 //set up for whole ones
1742                 while(ix1 != ix2)
1743                 {
1744                         //trapezoid(0,y1,1,y1+dydx);
1745                         current.addcover(dydx,dydx/2);  //accumulated area 1/2 the cover
1746
1747                         //move to next pixel (-1)
1748                         fy1 += dydx;
1749                         ix1--;
1750                         move_pen(ix1,y);
1751                 }
1752
1753                 //last pixel
1754                 mult = fy2 - fy1; //final y-pos - last intersect pos
1755
1756                 current.addcover(mult,(fx2+1)*mult/2);
1757         }
1758 }
1759
1760 void Layer_Shape::PolySpan::draw_line(Real x1, Real y1, Real x2, Real y2)
1761 {
1762         int iy1 = (int)floor(y1);
1763         int iy2 = (int)floor(y2);
1764         Real fy1 = y1 - iy1;
1765         Real fy2 = y2 - iy2;
1766
1767         assert(!isnan(fy1));
1768         assert(!isnan(fy2));
1769
1770         Real dx,dy,dxdy,mult,x_from,x_to;
1771
1772         const Real SLOPE_EPSILON = 1e-10;
1773
1774         //case all one scanline
1775         if(iy1 == iy2)
1776         {
1777                 draw_scanline(iy1,x1,y1,x2,y2);
1778                 return;
1779         }
1780
1781         //difference values
1782         dy = y2 - y1;
1783         dx = x2 - x1;
1784
1785         //case vertical line
1786         if(dx < SLOPE_EPSILON && dx > -SLOPE_EPSILON)
1787         {
1788                 //calc area and cover on vertical line
1789                 if(dy > 0)
1790                 {
1791                         // ---->        fx1...1  0...1  ...  0...1  0...fx2
1792                         Real sub;
1793
1794                         int      ix1 = (int)floor(x1);
1795                         Real fx1 = x1 - ix1;
1796
1797                         //current pixel
1798                         sub = 1 - fy1;
1799
1800                         current.addcover(sub,fx1*sub);
1801
1802                         //next pixel
1803                         iy1++;
1804
1805                         //move pen to next pixel
1806                         move_pen(ix1,iy1);
1807
1808                         while(iy1 != iy2)
1809                         {
1810                                 //accumulate cover
1811                                 current.addcover(1,fx1);
1812
1813                                 //next pixel
1814                                 iy1++;
1815                                 move_pen(ix1,iy1);
1816                         }
1817
1818                         //last pixel
1819                         current.addcover(fy2,fy2*fx1);
1820                 }else
1821                 {
1822                         Real sub;
1823
1824                         int      ix1 = (int)floor(x1);
1825                         Real fx1 = x1 - ix1;
1826
1827                         //current pixel
1828                         sub = 0 - fy1;
1829
1830                         current.addcover(sub,fx1*sub);
1831
1832                         //next pixel
1833                         iy1--;
1834
1835                         move_pen(ix1,iy1);
1836
1837                         while(iy1 != iy2)
1838                         {
1839                                 //accumulate in current pixel
1840                                 current.addcover(-1,-fx1);
1841
1842                                 //move to next
1843                                 iy1--;
1844                                 move_pen(ix1,iy1);
1845                         }
1846
1847                         current.addcover(fy2-1,(fy2-1)*fx1);
1848                 }
1849                 return;
1850         }
1851
1852         //case normal line - guaranteed dx != 0 && dy != 0
1853
1854         //calculate the initial intersection with "next" scanline
1855         if(dy > 0)
1856         {
1857                 dxdy = dx / dy;
1858
1859                 mult = (1 - fy1) * dxdy;
1860
1861                 //x interset scanline
1862                 x_from = x1 + mult;
1863                 draw_scanline(iy1,x1,fy1,x_from,1);
1864
1865                 //move to next line
1866                 iy1++;
1867
1868                 move_pen((int)floor(x_from),iy1);
1869
1870                 while(iy1 != iy2)
1871                 {
1872                         //keep up on the x axis, and render the current scanline
1873                         x_to = x_from + dxdy;
1874                         draw_scanline(iy1,x_from,0,x_to,1);
1875                         x_from = x_to;
1876
1877                         //move to next pixel
1878                         iy1++;
1879                         move_pen((int)floor(x_from),iy1);
1880                 }
1881
1882                 //draw the last one, fractional
1883                 draw_scanline(iy2,x_from,0,x2,fy2);
1884
1885         }else
1886         {
1887                 dxdy = -dx / dy;
1888
1889                 mult = fy1 * dxdy;
1890
1891                 //x interset scanline
1892                 x_from = x1 + mult;
1893                 draw_scanline(iy1,x1,fy1,x_from,0);
1894
1895                 //each line after
1896                 iy1--;
1897
1898                 move_pen((int)floor(x_from),iy1);
1899
1900                 while(iy1 != iy2)
1901                 {
1902                         x_to = x_from + dxdy;
1903                         draw_scanline(iy1,x_from,1,x_to,0);
1904                         x_from = x_to;
1905
1906                         iy1--;
1907                         move_pen((int)floor(x_from),iy1);
1908                 }
1909                 //draw the last one, fractional
1910                 draw_scanline(iy2,x_from,1,x2,fy2);
1911         }
1912 }
1913
1914 //****** LAYER PEN OPERATIONS (move_to, line_to, etc.) ******
1915 void Layer_Shape::move_to(Real x, Real y)
1916 {
1917         //const int sizeblock = sizeof(Primitive)+sizeof(Point);
1918         Primitive       op;
1919         Point           p(x,y);
1920
1921         op.operation = Primitive::MOVE_TO;
1922         op.number = 1;  //one point for now
1923
1924         if(lastbyteop == Primitive::MOVE_TO)
1925         {
1926                 char *ptr = &bytestream[lastoppos];
1927                 memcpy(ptr,&op,sizeof(op));
1928                 memcpy(ptr+sizeof(op),&p,sizeof(p));
1929         }
1930         else //make a new op
1931         {
1932                 lastbyteop = Primitive::MOVE_TO;
1933                 lastoppos = bytestream.size();
1934
1935                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));  //insert the bytes for the header
1936                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));    //insert the bytes for data
1937         }
1938
1939         edge_table->move_to(x,y);
1940 }
1941
1942 void Layer_Shape::close()
1943 {
1944         Primitive op;
1945
1946         op.operation = Primitive::CLOSE;
1947         op.number = 0;
1948
1949         if(lastbyteop == Primitive::CLOSE)
1950         {
1951         }else
1952         {
1953                 lastbyteop = Primitive::CLOSE;
1954                 lastoppos = bytestream.size();
1955
1956                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert header
1957         }
1958
1959         edge_table->close();
1960         //should not affect the bounding box since it would just be returning to old point...
1961 }
1962
1963 void Layer_Shape::endpath()
1964 {
1965         Primitive op;
1966
1967         op.operation = Primitive::END;
1968         op.number = 0;
1969
1970         if(lastbyteop == Primitive::END | lastbyteop == Primitive::NONE)
1971         {
1972         }else
1973         {
1974                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));
1975         }
1976         //should not affect the bounding box since it would just be returning to old point... if at all
1977 }
1978
1979 void Layer_Shape::line_to(Real x, Real y)
1980 {
1981         assert(!isnan(x));
1982         assert(!isnan(y));
1983
1984         //const int sizeblock = sizeof(Primitive)+sizeof(Point);
1985         Primitive       op;
1986         Point           p(x,y);
1987
1988         op.operation = Primitive::LINE_TO;
1989         op.number = 1;  //one point for now
1990
1991         if(lastbyteop == Primitive::MOVE_TO | lastbyteop == Primitive::LINE_TO)
1992         {
1993                 //only need to insert the point
1994                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
1995
1996                 Primitive * prim = (Primitive *)&bytestream[lastoppos];
1997                 prim->number++; //increment number of points in the list
1998         }else
1999         {
2000                 lastbyteop = Primitive::LINE_TO;
2001                 lastoppos = bytestream.size();
2002
2003                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));  //insert the bytes for the header
2004                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));    //insert the bytes for data
2005         }
2006
2007         edge_table->line_to(x,y);
2008 }
2009
2010 void Layer_Shape::conic_to(Real x1, Real y1, Real x, Real y)
2011 {
2012         //const int sizeblock = sizeof(Primitive)+sizeof(Point)*2;
2013         Primitive       op;
2014         Point           p(x,y);
2015         Point           p1(x1,y1);
2016
2017         op.operation = Primitive::CONIC_TO;
2018         op.number = 2;  //2 points for now
2019
2020         if(lastbyteop == Primitive::CONIC_TO)
2021         {
2022                 //only need to insert the new points
2023                 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
2024                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2025
2026                 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2027                 prim->number += 2; //increment number of points in the list
2028         }else
2029         {
2030                 lastbyteop = Primitive::CONIC_TO;
2031                 lastoppos = bytestream.size();
2032
2033                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));  //insert the bytes for the header
2034                 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));  //insert the bytes for data
2035                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));    //insert the bytes for data
2036         }
2037
2038         edge_table->conic_to(x1,y1,x,y);
2039 }
2040
2041 void Layer_Shape::conic_to_smooth(Real x, Real y)                               //x1,y1 derived from current tangent
2042 {
2043         //const int sizeblock = sizeof(Primitive)+sizeof(Point);
2044         Primitive       op;
2045         Point           p(x,y);
2046
2047         op.operation = Primitive::CONIC_TO_SMOOTH;
2048         op.number = 1;  //2 points for now
2049
2050         if(lastbyteop == Primitive::CONIC_TO_SMOOTH)
2051         {
2052                 //only need to insert the new point
2053                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2054
2055                 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2056                 prim->number += 1; //increment number of points in the list
2057         }else
2058         {
2059                 lastbyteop = Primitive::CONIC_TO_SMOOTH;
2060                 lastoppos = bytestream.size();
2061
2062                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));  //insert the bytes for the header
2063                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));    //insert the bytes for data
2064         }
2065
2066         edge_table->conic_to_smooth(x,y);
2067 }
2068
2069 void Layer_Shape::curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
2070 {
2071         //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3;
2072         Primitive       op;
2073         Point           p(x,y);
2074         Point           p1(x1,y1);
2075         Point           p2(x2,y2);
2076
2077         op.operation = Primitive::CUBIC_TO;
2078         op.number = 3;  //3 points for now
2079
2080         if(lastbyteop == Primitive::CUBIC_TO)
2081         {
2082                 //only need to insert the new points
2083                 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
2084                 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
2085                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2086
2087                 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2088                 prim->number += 3; //increment number of points in the list
2089         }else
2090         {
2091                 lastbyteop = Primitive::CUBIC_TO;
2092                 lastoppos = bytestream.size();
2093
2094                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));  //insert the bytes for the header
2095                 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));  //insert the bytes for data
2096                 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));  //insert the bytes for data
2097                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));    //insert the bytes for data
2098         }
2099
2100         edge_table->curve_to(x1,y1,x2,y2,x,y);
2101 }
2102
2103 void Layer_Shape::curve_to_smooth(Real x2, Real y2, Real x, Real y)             //x1,y1 derived from current tangent
2104 {
2105         //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3;
2106         Primitive       op;
2107         Point           p(x,y);
2108         Point           p2(x2,y2);
2109
2110         op.operation = Primitive::CUBIC_TO_SMOOTH;
2111         op.number = 2;  //3 points for now
2112
2113         if(lastbyteop == Primitive::CUBIC_TO_SMOOTH)
2114         {
2115                 //only need to insert the new points
2116                 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
2117                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2118
2119                 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2120                 prim->number += 2; //increment number of points in the list
2121         }else
2122         {
2123                 lastbyteop = Primitive::CUBIC_TO_SMOOTH;
2124                 lastoppos = bytestream.size();
2125
2126                 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));  //insert the bytes for the header
2127                 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));  //insert the bytes for data
2128                 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));    //insert the bytes for data
2129         }
2130 }
2131
2132 // ACCELERATED RENDER FUNCTION - TRANSLATE BYTE CODE INTO FUNCTION CALLS
2133
2134 bool Layer_Shape::render_polyspan(Surface *surface, PolySpan &polyspan,
2135                                                                 Color::BlendMethod got_blend_method, Color::value_type got_amount) const
2136 {
2137         Surface::alpha_pen p(surface->begin(),got_amount,_BlendFunc(got_blend_method));
2138         PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin();
2139         PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
2140
2141         Real cover,area,alpha;
2142
2143         int     y,x;
2144
2145         p.set_value(color);
2146         cover = 0;
2147
2148         if(cur_mark == end_mark)
2149         {
2150                 //no marks at all
2151                 if(invert)
2152                 {
2153                         p.move_to(polyspan.window.minx,polyspan.window.miny);
2154                         p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx);
2155                 }
2156                 return true;
2157         }
2158
2159         //fill initial rect / line
2160         if(invert)
2161         {
2162                 //fill all the area above the first vertex
2163                 p.move_to(polyspan.window.minx,polyspan.window.miny);
2164                 y = polyspan.window.miny;
2165                 int l = polyspan.window.maxx - polyspan.window.minx;
2166
2167                 p.put_block(cur_mark->y - polyspan.window.miny,l);
2168
2169                 //fill the area to the left of the first vertex on that line
2170                 l = cur_mark->x - polyspan.window.minx;
2171                 p.move_to(polyspan.window.minx,cur_mark->y);
2172                 if(l) p.put_hline(l);
2173         }
2174
2175         for(;;)
2176         {
2177                 y = cur_mark->y;
2178                 x = cur_mark->x;
2179
2180                 p.move_to(x,y);
2181
2182                 area = cur_mark->area;
2183                 cover += cur_mark->cover;
2184
2185                 //accumulate for the current pixel
2186                 while(++cur_mark != polyspan.covers.end())
2187                 {
2188                         if(y != cur_mark->y | x != cur_mark->x)
2189                                 break;
2190
2191                         area += cur_mark->area;
2192                         cover += cur_mark->cover;
2193                 }
2194
2195                 //draw pixel - based on covered area
2196                 if(area)        //if we're ok, draw the current pixel
2197                 {
2198                         alpha = polyspan.ExtractAlpha(cover - area);
2199                         if(invert) alpha = 1 - alpha;
2200
2201                         if(!antialias)
2202                         {
2203                                 if(alpha >= .5) p.put_value();
2204                         }
2205                         else if(alpha) p.put_value_alpha(alpha);
2206
2207                         p.inc_x();
2208                         x++;
2209                 }
2210
2211                 //if we're done, don't use iterator and exit
2212                 if(cur_mark == end_mark) break;
2213
2214                 //if there is no more live pixels on this line, goto next
2215                 if(y != cur_mark->y)
2216                 {
2217                         if(invert)
2218                         {
2219                                 //fill the area at the end of the line
2220                                 p.put_hline(polyspan.window.maxx - x);
2221
2222                                 //fill area at the beginning of the next line
2223                                 p.move_to(polyspan.window.minx,cur_mark->y);
2224                                 p.put_hline(cur_mark->x - polyspan.window.minx);
2225                         }
2226
2227                         cover = 0;
2228
2229                         continue;
2230                 }
2231
2232                 //draw span to next pixel - based on total amount of pixel cover
2233                 if(x < cur_mark->x)
2234                 {
2235                         alpha = polyspan.ExtractAlpha(cover);
2236                         if(invert) alpha = 1 - alpha;
2237
2238                         if(!antialias)
2239                         {
2240                                 if(alpha >= .5) p.put_hline(cur_mark->x - x);
2241                         }
2242                         else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2243                 }
2244         }
2245
2246         //fill the after stuff
2247         if(invert)
2248         {
2249                 //fill the area at the end of the line
2250                 p.put_hline(polyspan.window.maxx - x);
2251
2252                 //fill area at the beginning of the next line
2253                 p.move_to(polyspan.window.minx,y+1);
2254                 p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
2255         }
2256
2257         return true;
2258 }
2259
2260 bool Layer_Shape::render_polyspan(etl::surface<float> *surface, PolySpan &polyspan) const
2261 {
2262         etl::surface<float>::pen p(surface->begin());
2263         PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin();
2264         PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
2265
2266         Real cover,area,alpha;
2267
2268         int     y,x;
2269
2270         cover = 0;
2271
2272         //the pen always writes 1 (unless told to do otherwise)
2273         p.set_value(1);
2274
2275         if(cur_mark == end_mark)
2276         {
2277                 //no marks at all
2278                 if(invert)
2279                 {
2280                         p.move_to(polyspan.window.minx,polyspan.window.miny);
2281                         p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx);
2282                 }
2283                 return true;
2284         }
2285
2286         //fill initial rect / line
2287         if(invert)
2288         {
2289                 //fill all the area above the first vertex
2290                 p.move_to(polyspan.window.minx,polyspan.window.miny);
2291                 y = polyspan.window.miny;
2292                 int l = polyspan.window.maxx - polyspan.window.minx;
2293
2294                 p.put_block(cur_mark->y - polyspan.window.miny,l);
2295
2296                 //fill the area to the left of the first vertex on that line
2297                 l = cur_mark->x - polyspan.window.minx;
2298                 p.move_to(polyspan.window.minx,cur_mark->y);
2299                 if(l) p.put_hline(l);
2300
2301                 for(;;)
2302                 {
2303                         y = cur_mark->y;
2304                         x = cur_mark->x;
2305
2306                         p.move_to(x,y);
2307
2308                         area = cur_mark->area;
2309                         cover += cur_mark->cover;
2310
2311                         //accumulate for the current pixel
2312                         while(++cur_mark != polyspan.covers.end())
2313                         {
2314                                 if(y != cur_mark->y | x != cur_mark->x)
2315                                         break;
2316
2317                                 area += cur_mark->area;
2318                                 cover += cur_mark->cover;
2319                         }
2320
2321                         //draw pixel - based on covered area
2322                         if(area)        //if we're ok, draw the current pixel
2323                         {
2324                                 alpha = 1 - polyspan.ExtractAlpha(cover - area);
2325                                 if(!antialias)
2326                                 {
2327                                         if(alpha >= .5) p.put_value();
2328                                 }
2329                                 else if(alpha) p.put_value(alpha);
2330
2331                                 p.inc_x();
2332                                 x++;
2333                         }
2334
2335                         //if we're done, don't use iterator and exit
2336                         if(cur_mark == end_mark) break;
2337
2338                         //if there is no more live pixels on this line, goto next
2339                         if(y != cur_mark->y)
2340                         {
2341                                 //fill the area at the end of the line
2342                                 p.put_hline(polyspan.window.maxx - x);
2343
2344                                 //fill area at the beginning of the next line
2345                                 p.move_to(polyspan.window.minx,cur_mark->y);
2346                                 p.put_hline(cur_mark->x - polyspan.window.minx);
2347
2348                                 cover = 0;
2349
2350                                 continue;
2351                         }
2352
2353                         //draw span to next pixel - based on total amount of pixel cover
2354                         if(x < cur_mark->x)
2355                         {
2356                                 alpha = 1 - polyspan.ExtractAlpha(cover);
2357                                 if(!antialias)
2358                                 {
2359                                         if(alpha >= .5) p.put_hline(cur_mark->x - x);
2360                                 }
2361                                 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2362                         }
2363                 }
2364
2365                 //fill the area at the end of the line
2366                 p.put_hline(polyspan.window.maxx - x);
2367
2368                 //fill area at the beginning of the next line
2369                 p.move_to(polyspan.window.minx,y+1);
2370                 p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
2371         }else
2372         {
2373                 for(;;)
2374                 {
2375                         y = cur_mark->y;
2376                         x = cur_mark->x;
2377
2378                         p.move_to(x,y);
2379
2380                         area = cur_mark->area;
2381                         cover += cur_mark->cover;
2382
2383                         //accumulate for the current pixel
2384                         while(++cur_mark != polyspan.covers.end())
2385                         {
2386                                 if(y != cur_mark->y | x != cur_mark->x)
2387                                         break;
2388
2389                                 area += cur_mark->area;
2390                                 cover += cur_mark->cover;
2391                         }
2392
2393                         //draw pixel - based on covered area
2394                         if(area)        //if we're ok, draw the current pixel
2395                         {
2396                                 alpha = polyspan.ExtractAlpha(cover - area);
2397                                 if(!antialias)
2398                                 {
2399                                         if(alpha >= .5) p.put_value();
2400                                 }
2401                                 else if(alpha) p.put_value(alpha);
2402
2403                                 p.inc_x();
2404                                 x++;
2405                         }
2406
2407                         //if we're done, don't use iterator and exit
2408                         if(cur_mark == end_mark) break;
2409
2410                         //if there is no more live pixels on this line, goto next
2411                         if(y != cur_mark->y)
2412                         {
2413                                 cover = 0;
2414
2415                                 continue;
2416                         }
2417
2418                         //draw span to next pixel - based on total amount of pixel cover
2419                         if(x < cur_mark->x)
2420                         {
2421                                 alpha = polyspan.ExtractAlpha(cover);
2422                                 if(!antialias)
2423                                 {
2424                                         if(alpha >= .5) p.put_hline(cur_mark->x - x);
2425                                 }
2426                                 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2427                         }
2428                 }
2429         }
2430
2431         return true;
2432 }
2433
2434 bool
2435 Layer_Shape::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
2436 {
2437         const unsigned int w = renddesc.get_w();
2438         const unsigned int h = renddesc.get_h();
2439
2440         const Real pw = abs(renddesc.get_pw());
2441         const Real ph = abs(renddesc.get_ph());
2442
2443         //const Real OFFSET_EPSILON = 1e-8;
2444         SuperCallback stageone(cb,1,10000,15001+renddesc.get_h());
2445         SuperCallback stagetwo(cb,10000,10001+renddesc.get_h(),15001+renddesc.get_h());
2446         SuperCallback stagethree(cb,10001+renddesc.get_h(),15001+renddesc.get_h(),15001+renddesc.get_h());
2447
2448         // Render what is behind us
2449
2450         //clip if it satisfies the invert solid thing
2451         if(is_solid_color() && invert)
2452         {
2453                 Rect aabb = edge_table->aabb;
2454                 Point tl = renddesc.get_tl() - offset;
2455
2456                 Real    pw = renddesc.get_pw(),
2457                                 ph = renddesc.get_ph();
2458
2459                 Rect    nrect;
2460
2461                 Real    pixelfeatherx = abs(feather/pw),
2462                                 pixelfeathery = abs(feather/ph);
2463
2464                 nrect.set_point((aabb.minx - tl[0])/pw,(aabb.miny - tl[1])/ph);
2465                 nrect.expand((aabb.maxx - tl[0])/pw,(aabb.maxy - tl[1])/ph);
2466
2467                 RendDesc        optdesc(renddesc);
2468
2469                 //make sure to expand so we gain subpixels rather than lose them
2470                 nrect.minx = floor(nrect.minx-pixelfeatherx); nrect.miny = floor(nrect.miny-pixelfeathery);
2471                 nrect.maxx = ceil(nrect.maxx+pixelfeatherx); nrect.maxy = ceil(nrect.maxy+pixelfeathery);
2472
2473                 //make sure the subwindow is clipped with our tile window (minimize useless drawing)
2474                 set_intersect(nrect,nrect,Rect(0,0,renddesc.get_w(),renddesc.get_h()));
2475
2476                 //must resize the surface first
2477                 surface->set_wh(renddesc.get_w(),renddesc.get_h());
2478                 surface->clear();
2479
2480                 //only render anything if it's visible from our current tile
2481                 if(nrect.valid())
2482                 {
2483                         //set the subwindow to the viewable pixels and render it to the subsurface
2484                         optdesc.set_subwindow((int)nrect.minx, (int)nrect.miny,
2485                                 (int)(nrect.maxx - nrect.minx), (int)(nrect.maxy - nrect.miny));
2486
2487                         Surface optimizedbacksurf;
2488                         if(!context.accelerated_render(&optimizedbacksurf,quality,optdesc,&stageone))
2489                                 return false;
2490
2491                         //blit that onto the original surface so we can pretend that nothing ever happened
2492                         Surface::pen p = surface->get_pen((int)nrect.minx,(int)nrect.miny);
2493                         optimizedbacksurf.blit_to(p);
2494                 }
2495         }else
2496         {
2497                 if(!context.accelerated_render(surface,quality,renddesc,&stageone))
2498                         return false;
2499         }
2500
2501         if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
2502
2503         if(feather)
2504         {
2505                 //we have to blur rather than be crappy
2506
2507                 //so make a separate surface
2508                 RendDesc        workdesc(renddesc);
2509
2510                 etl::surface<float>     shapesurface;
2511
2512                 //the expanded size = 1/2 the size in each direction rounded up
2513                 int     halfsizex = (int) (abs(feather*.5/pw) + 3),
2514                         halfsizey = (int) (abs(feather*.5/ph) + 3);
2515
2516                 //expand by 1/2 size in each direction on either side
2517                 switch(blurtype)
2518                 {
2519                         case Blur::DISC:
2520                         case Blur::BOX:
2521                         case Blur::CROSS:
2522                         {
2523                                 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey));
2524                                 break;
2525                         }
2526                         case Blur::FASTGAUSSIAN:
2527                         {
2528                                 if(quality < 4)
2529                                 {
2530                                         halfsizex*=2;
2531                                         halfsizey*=2;
2532                                 }
2533                                 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey));
2534                                 break;
2535                         }
2536                         case Blur::GAUSSIAN:
2537                         {
2538                         #define GAUSSIAN_ADJUSTMENT             (0.05)
2539                                 Real    pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
2540                                 Real    ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
2541
2542                                 pw=pw*pw;
2543                                 ph=ph*ph;
2544
2545                                 halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5);
2546                                 halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5);
2547
2548                                 halfsizex = (halfsizex + 1)/2;
2549                                 halfsizey = (halfsizey + 1)/2;
2550                                 workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey );
2551
2552                                 break;
2553                         }
2554                 }
2555
2556                 shapesurface.set_wh(workdesc.get_w(),workdesc.get_h());
2557                 shapesurface.clear();
2558
2559                 //render the shape
2560                 if(!render_shape(&shapesurface,quality,workdesc,&stagetwo))return false;
2561
2562                 //blur the image
2563                 Blur(feather,feather,blurtype,&stagethree)(shapesurface,workdesc.get_br()-workdesc.get_tl(),shapesurface);
2564
2565                 //blend with stuff below it...
2566                 unsigned int u = halfsizex, v = halfsizey, x = 0, y = 0;
2567                 for(y = 0; y < h; y++,v++)
2568                 {
2569                         u = halfsizex;
2570                         for(x = 0; x < w; x++,u++)
2571                         {
2572                                 float a = shapesurface[v][u];
2573                                 if(a)
2574                                 {
2575                                         //a = floor(a*255+0.5f)/255;
2576                                         (*surface)[y][x]=Color::blend(color,(*surface)[y][x],a*get_amount(),get_blend_method());
2577                                 }
2578                                 //else (*surface)[y][x] = worksurface[v][u];
2579                         }
2580                 }
2581
2582                 //we are done
2583                 if(cb && !cb->amount_complete(100,100))
2584                 {
2585                         synfig::warning("Layer_Shape: could not set amount complete");
2586                         return false;
2587                 }
2588
2589                 return true;
2590         }else
2591         {
2592                 //might take out to reduce code size
2593                 return render_shape(surface,true,quality,renddesc,&stagetwo);
2594         }
2595
2596 }
2597
2598 bool
2599 Layer_Shape::render_shape(Surface *surface,bool useblend,int quality,
2600                                                         const RendDesc &renddesc, ProgressCallback *cb)const
2601 {
2602         int tmp(0);
2603
2604         SuperCallback   progress(cb,0,renddesc.get_h(),renddesc.get_h());
2605
2606         // If our amount is set to zero, no need to render anything
2607         if(!get_amount())
2608                 return true;
2609
2610         //test new polygon renderer
2611         // Build edge table
2612         // Width and Height of a pixel
2613         const int       w = renddesc.get_w();
2614         const int       h = renddesc.get_h();
2615         const Real      pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
2616         const Real      ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
2617
2618         const Point     tl = renddesc.get_tl();
2619
2620         Vector tangent (0,0);
2621
2622         PolySpan        span;
2623
2624         //optimization for tesselating only inside tiles
2625         span.window.minx = 0;
2626         span.window.miny = 0;
2627         span.window.maxx = w;
2628         span.window.maxy = h;
2629
2630         //pointers for processing the bytestream
2631         const char *current     = &bytestream[0];
2632         const char *end                 = &bytestream[bytestream.size()];
2633
2634         int     operation       = Primitive::NONE;
2635         int number              = 0;
2636         int curnum;
2637
2638         Primitive       *curprim;
2639         Point           *data;
2640
2641         Real x,y,x1,y1,x2,y2;
2642
2643
2644         while(current < end)
2645         {
2646                 tmp++;
2647
2648                 try {
2649
2650                 //get the op code safely
2651                 curprim = (Primitive *)current;
2652
2653                 //advance past indices
2654                 current += sizeof(Primitive);
2655                 if(current > end)
2656                 {
2657                         warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
2658                         return false;
2659                 }
2660
2661                 //get the relevant data
2662                 operation       = curprim->operation;
2663                 number          = curprim->number;
2664
2665                 if(operation == Primitive::END)
2666                         break;
2667
2668                 if(operation == Primitive::CLOSE)
2669                 {
2670                         if(span.notclosed())
2671                         {
2672                                 tangent[0] = span.close_x - span.cur_x;
2673                                 tangent[1] = span.close_y - span.cur_y;
2674                                 span.close();
2675                         }
2676                         continue;
2677                 }
2678
2679                 data = (Point*)current;
2680                 current += sizeof(Point)*number;
2681
2682                 //check data positioning
2683                 if(current > end)
2684                 {
2685                         warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points");
2686                         return false;
2687                 }
2688
2689                 } catch(...) { synfig::error("Layer_Shape::render_shape()1: Caught an exception after %d loops, rethrowing...", tmp); throw; }
2690
2691                 //transfer all the data - RLE optimized
2692                 for(curnum=0; curnum < number;)
2693                 {
2694                         switch(operation)
2695                         {
2696                                 case Primitive::MOVE_TO:
2697                                 {
2698                                         x = data[curnum][0];
2699                                         x = (x - tl[0] + offset[0])*pw;
2700                                         y = data[curnum][1];
2701                                         y = (y - tl[1] + offset[1])*ph;
2702
2703                                         if(curnum == 0)
2704                                         {
2705                                                 span.move_to(x,y);
2706
2707                                                 tangent[0] = 0;
2708                                                 tangent[1] = 0;
2709                                         }
2710                                         else
2711                                         {
2712                                                 tangent[0] = x - span.cur_x;
2713                                                 tangent[1] = y - span.cur_y;
2714
2715                                                 span.line_to(x,y);
2716                                         }
2717
2718                                         curnum++; //only advance one point
2719
2720                                         break;
2721                                 }
2722
2723                                 case Primitive::LINE_TO:
2724                                 {
2725                                         x = data[curnum][0];
2726                                         x = (x - tl[0] + offset[0])*pw;
2727                                         y = data[curnum][1];
2728                                         y = (y - tl[1] + offset[1])*ph;
2729
2730                                         tangent[0] = x - span.cur_x;
2731                                         tangent[1] = y - span.cur_y;
2732
2733                                         span.line_to(x,y);
2734                                         curnum++;
2735                                         break;
2736                                 }
2737
2738                                 case Primitive::CONIC_TO:
2739                                 {
2740                                         x = data[curnum+1][0];
2741                                         x = (x - tl[0] + offset[0])*pw;
2742                                         y = data[curnum+1][1];
2743                                         y = (y - tl[1] + offset[1])*ph;
2744
2745                                         x1 = data[curnum][0];
2746                                         x1 = (x1 - tl[0] + offset[0])*pw;
2747                                         y1 = data[curnum][1];
2748                                         y1 = (y1 - tl[1] + offset[1])*ph;
2749
2750                                         tangent[0] = 2*(x - x1);
2751                                         tangent[1] = 2*(y - y1);
2752
2753                                         span.conic_to(x1,y1,x,y);
2754                                         curnum += 2;
2755                                         break;
2756                                 }
2757
2758                                 case Primitive::CONIC_TO_SMOOTH:
2759                                 {
2760                                         x = data[curnum][0];
2761                                         x = (x - tl[0] + offset[0])*pw;
2762                                         y = data[curnum][1];
2763                                         y = (y - tl[1] + offset[1])*ph;
2764
2765                                         x1 = span.cur_x + tangent[0]/2;
2766                                         y1 = span.cur_y + tangent[1]/2;
2767
2768                                         tangent[0] = 2*(x - x1);
2769                                         tangent[1] = 2*(y - y1);
2770
2771                                         span.conic_to(x1,y1,x,y);
2772                                         curnum ++;
2773
2774                                         break;
2775                                 }
2776
2777                                 case Primitive::CUBIC_TO:
2778                                 {
2779                                         x = data[curnum+2][0];
2780                                         x = (x - tl[0] + offset[0])*pw;
2781                                         y = data[curnum+2][1];
2782                                         y = (y - tl[1] + offset[1])*ph;
2783
2784                                         x2 = data[curnum+1][0];
2785                                         x2 = (x2 - tl[0] + offset[0])*pw;
2786                                         y2 = data[curnum+1][1];
2787                                         y2 = (y2 - tl[1] + offset[1])*ph;
2788
2789                                         x1 = data[curnum][0];
2790                                         x1 = (x1 - tl[0] + offset[0])*pw;
2791                                         y1 = data[curnum][1];
2792                                         y1 = (y1 - tl[1] + offset[1])*ph;
2793
2794                                         tangent[0] = 2*(x - x2);
2795                                         tangent[1] = 2*(y - y2);
2796
2797                                         span.cubic_to(x1,y1,x2,y2,x,y);
2798                                         curnum += 3;
2799
2800                                         break;
2801                                 }
2802
2803                                 case Primitive::CUBIC_TO_SMOOTH:
2804                                 {
2805                                         x = data[curnum+1][0];
2806                                         x = (x - tl[0] + offset[0])*pw;
2807                                         y = data[curnum+1][1];
2808                                         y = (y - tl[1] + offset[1])*ph;
2809
2810                                         x2 = data[curnum][0];
2811                                         x2 = (x2 - tl[0] + offset[0])*pw;
2812                                         y2 = data[curnum][1];
2813                                         y2 = (y2 - tl[1] + offset[1])*ph;
2814
2815                                         x1 = span.cur_x + tangent[0]/3.0;
2816                                         y1 = span.cur_y + tangent[1]/3.0;
2817
2818                                         tangent[0] = 2*(x - x2);
2819                                         tangent[1] = 2*(y - y2);
2820
2821                                         span.cubic_to(x1,y1,x2,y2,x,y);
2822                                         curnum += 2;
2823
2824                                         break;
2825                                 }
2826                         }
2827                 }
2828         }
2829
2830         //sort the bastards so we can render everything
2831         span.sort_marks();
2832
2833         return render_polyspan(surface, span,
2834                         useblend?get_blend_method():Color::BLEND_STRAIGHT,
2835                         useblend?get_amount():1.0);
2836 }
2837
2838 bool
2839 Layer_Shape::render_shape(surface<float> *surface,int quality,
2840                                                         const RendDesc &renddesc, ProgressCallback *cb)const
2841 {
2842         // If our amount is set to zero, no need to render anything
2843         if(!get_amount())
2844                 return true;
2845
2846         //test new polygon renderer
2847         // Build edge table
2848         // Width and Height of a pixel
2849         const int       w = renddesc.get_w();
2850         const int       h = renddesc.get_h();
2851         const Real      pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
2852         const Real      ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
2853
2854         const Point     tl = renddesc.get_tl();
2855
2856         Vector tangent (0,0);
2857
2858         PolySpan        span;
2859
2860         //optimization for tesselating only inside tiles
2861         span.window.minx = 0;
2862         span.window.miny = 0;
2863         span.window.maxx = w;
2864         span.window.maxy = h;
2865
2866         //pointers for processing the bytestream
2867         const char *current     = &bytestream[0];
2868         const char *end                 = &bytestream[bytestream.size()];
2869
2870         int     operation       = Primitive::NONE;
2871         int number              = 0;
2872         int curnum;
2873
2874         Primitive       *curprim;
2875         Point           *data;
2876
2877         Real x,y,x1,y1,x2,y2;
2878
2879         while(current < end)
2880         {
2881                 //get the op code safely
2882                 curprim = (Primitive *)current;
2883
2884                 //advance past indices
2885                 current += sizeof(Primitive);
2886                 if(current > end)
2887                 {
2888                         warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
2889                         return false;
2890                 }
2891
2892                 //get the relevant data
2893                 operation       = curprim->operation;
2894                 number          = curprim->number;
2895
2896                 if(operation == Primitive::END)
2897                         break;
2898
2899                 if(operation == Primitive::CLOSE)
2900                 {
2901                         if(span.notclosed())
2902                         {
2903                                 tangent[0] = span.close_x - span.cur_x;
2904                                 tangent[1] = span.close_y - span.cur_y;
2905                                 span.close();
2906                         }
2907                         continue;
2908                 }
2909
2910                 data = (Point*)current;
2911                 current += sizeof(Point)*number;
2912
2913                 //check data positioning
2914                 if(current > end)
2915                 {
2916                         warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points");
2917                         return false;
2918                 }
2919
2920                 //transfer all the data
2921                 for(curnum=0; curnum < number;)
2922                 {
2923                         switch(operation)
2924                         {
2925                                 case Primitive::MOVE_TO:
2926                                 {
2927                                         x = data[curnum][0];
2928                                         x = (x - tl[0] + offset[0])*pw;
2929                                         y = data[curnum][1];
2930                                         y = (y - tl[1] + offset[1])*ph;
2931
2932                                         if(curnum == 0)
2933                                         {
2934                                                 span.move_to(x,y);
2935
2936                                                 tangent[0] = 0;
2937                                                 tangent[1] = 0;
2938                                         }
2939                                         else
2940                                         {
2941                                                 tangent[0] = x - span.cur_x;
2942                                                 tangent[1] = y - span.cur_y;
2943
2944                                                 span.line_to(x,y);
2945                                         }
2946
2947                                         curnum++; //only advance one point
2948
2949                                         break;
2950                                 }
2951
2952                                 case Primitive::LINE_TO:
2953                                 {
2954                                         x = data[curnum][0];
2955                                         x = (x - tl[0] + offset[0])*pw;
2956                                         y = data[curnum][1];
2957                                         y = (y - tl[1] + offset[1])*ph;
2958
2959                                         tangent[0] = x - span.cur_x;
2960                                         tangent[1] = y - span.cur_y;
2961
2962                                         span.line_to(x,y);
2963                                         curnum++;
2964                                         break;
2965                                 }
2966
2967                                 case Primitive::CONIC_TO:
2968                                 {
2969                                         x = data[curnum+1][0];
2970                                         x = (x - tl[0] + offset[0])*pw;
2971                                         y = data[curnum+1][1];
2972                                         y = (y - tl[1] + offset[1])*ph;
2973
2974                                         x1 = data[curnum][0];
2975                                         x1 = (x1 - tl[0] + offset[0])*pw;
2976                                         y1 = data[curnum][1];
2977                                         y1 = (y1 - tl[1] + offset[1])*ph;
2978
2979                                         tangent[0] = 2*(x - x1);
2980                                         tangent[1] = 2*(y - y1);
2981
2982                                         span.conic_to(x1,y1,x,y);
2983                                         curnum += 2;
2984                                         break;
2985                                 }
2986
2987                                 case Primitive::CONIC_TO_SMOOTH:
2988                                 {
2989                                         x = data[curnum][0];
2990                                         x = (x - tl[0] + offset[0])*pw;
2991                                         y = data[curnum][1];
2992                                         y = (y - tl[1] + offset[1])*ph;
2993
2994                                         x1 = span.cur_x + tangent[0]/2;
2995                                         y1 = span.cur_y + tangent[1]/2;
2996
2997                                         tangent[0] = 2*(x - x1);
2998                                         tangent[1] = 2*(y - y1);
2999
3000                                         span.conic_to(x1,y1,x,y);
3001                                         curnum ++;
3002
3003                                         break;
3004                                 }
3005
3006                                 case Primitive::CUBIC_TO:
3007                                 {
3008                                         x = data[curnum+2][0];
3009                                         x = (x - tl[0] + offset[0])*pw;
3010                                         y = data[curnum+2][1];
3011                                         y = (y - tl[1] + offset[1])*ph;
3012
3013                                         x2 = data[curnum+1][0];
3014                                         x2 = (x2 - tl[0] + offset[0])*pw;
3015                                         y2 = data[curnum+1][1];
3016                                         y2 = (y2 - tl[1] + offset[1])*ph;
3017
3018                                         x1 = data[curnum][0];
3019                                         x1 = (x1 - tl[0] + offset[0])*pw;
3020                                         y1 = data[curnum][1];
3021                                         y1 = (y1 - tl[1] + offset[1])*ph;
3022
3023                                         tangent[0] = 2*(x - x2);
3024                                         tangent[1] = 2*(y - y2);
3025
3026                                         span.cubic_to(x1,y1,x2,y2,x,y);
3027                                         curnum += 3;
3028
3029                                         break;
3030                                 }
3031
3032                                 case Primitive::CUBIC_TO_SMOOTH:
3033                                 {
3034                                         x = data[curnum+1][0];
3035                                         x = (x - tl[0] + offset[0])*pw;
3036                                         y = data[curnum+1][1];
3037                                         y = (y - tl[1] + offset[1])*ph;
3038
3039                                         x2 = data[curnum][0];
3040                                         x2 = (x2 - tl[0] + offset[0])*pw;
3041                                         y2 = data[curnum][1];
3042                                         y2 = (y2 - tl[1] + offset[1])*ph;
3043
3044                                         x1 = span.cur_x + tangent[0]/3.0;
3045                                         y1 = span.cur_y + tangent[1]/3.0;
3046
3047                                         tangent[0] = 2*(x - x2);
3048                                         tangent[1] = 2*(y - y2);
3049
3050                                         span.cubic_to(x1,y1,x2,y2,x,y);
3051                                         curnum += 2;
3052
3053                                         break;
3054                                 }
3055                         }
3056                 }
3057         }
3058
3059         //sort the bastards so we can render everything
3060         span.sort_marks();
3061
3062         return render_polyspan(surface, span);
3063 }
3064
3065 Rect
3066 Layer_Shape::get_bounding_rect()const
3067 {
3068         if(invert)
3069                 return Rect::full_plane();
3070
3071         if (edge_table->initaabb)
3072                 return Rect::zero();
3073
3074         Rect bounds(edge_table->aabb+offset);
3075         bounds.expand(max((bounds.get_min() - bounds.get_max()).mag()*0.01,
3076                                           feather));
3077
3078         return bounds;
3079 }