1 /* === S Y N F I G ========================================================= */
2 /*! \file layer_shape.cpp
3 ** \brief Template Header
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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.
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.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include "layer_shape.h"
36 #include "paramdesc.h"
40 #include "valuenode.h"
44 #include "curve_helper.h"
52 /* === U S I N G =========================================================== */
54 using namespace synfig;
58 /* === G L O B A L S ======================================================= */
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$");
70 inline bool IsZero(const T &n)
72 return (n < EPSILON) && (n > -EPSILON);
75 /* === C L A S S E S ======================================================= */
77 //Assumes 64 byte aligned structures if at all
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)+ " "
99 //******** CURVE FUNCTIONS *****************
100 const int MAX_SUBDIVISION_SIZE = 64;
101 const int MIN_SUBDIVISION_DRAW_LEVELS = 4;
103 static void Subd_Conic_Stack(Point *arc)
121 arc[4][0] = arc[2][0];
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;
129 arc[4][1] = arc[2][1];
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;
140 arc[3] = (arc[2] + arc[1])/2;
141 arc[1] = (arc[0] + arc[1])/2;
143 arc[2] = (arc[1] + arc[3])/2;
149 static void Subd_Cubic_Stack(Point *arc)
158 * 1+2 b * 0+3*1+3*2+3
164 0.1 2.3 -> 0.1 2 3 4 5.6
168 arc[6][0] = arc[3][0];
173 a = arc[1][0] = (arc[0][0] + b)/2;
175 c = arc[5][0] = (arc[6][0] + c)/2;
177 a = arc[2][0] = (a + b)/2;
178 b = arc[4][0] = (b + c)/2;
180 arc[3][0] = (a + b)/2;
183 arc[6][1] = arc[3][1];
188 a = arc[1][1] = (arc[0][1] + b)/2;
190 c = arc[5][1] = (arc[6][1] + c)/2;
192 a = arc[2][1] = (a + b)/2;
193 b = arc[4][1] = (b + c)/2;
195 arc[3][1] = (a + b)/2;
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;
207 arc[4] = (temp + arc[5])/2;
208 arc[2] = (arc[1] + temp)/2;
210 arc[3] = (arc[2] + arc[4])/2;
215 //************** PARAMETRIC RENDERER SUPPORT STRUCTURES ****************
222 vector<Point> pointlist;
224 MonoSegment(int dir = 0, Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
234 int intersect(Real x,Real y) const
236 if((y < aabb.miny+EPSILON) || (y > aabb.maxy) || (x < aabb.minx)) return 0;
237 if(x > aabb.maxx) return ydir;
240 //int size = pointlist.size();
241 //vector<Point>::const_iterator end = pointlist.end();
242 vector<Point>::const_iterator p = pointlist.begin();
244 //assumes that the rect culled away anything that would be beyond the edges
247 while(y > (*++p)[1]);
251 while(y < (*++p)[1]);
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];
261 Real xi = p[0][0] + (y - p[0][1]) * dx / dy;
262 return (x > xi)*ydir;
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;
272 CurveArray(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
274 aabb.set(x0,y0,x1,y1);
277 void reset(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
279 aabb.set(x0,y0,x1,y1);
286 return degrees.size();
291 reset(m[0],m[0],m[1],m[1]);
292 pointlist.push_back(m);
295 void AddCubic(Point p1, Point p2, Point dest)
297 aabb.expand(p1[0],p1[1]);
298 aabb.expand(p2[0],p2[1]);
299 aabb.expand(dest[0],dest[1]);
301 pointlist.push_back(p1);
302 pointlist.push_back(p2);
303 pointlist.push_back(dest);
305 degrees.push_back(3);
308 void AddConic(Point p1, Point dest)
310 aabb.expand(p1[0],p1[1]);
311 aabb.expand(dest[0],dest[1]);
313 pointlist.push_back(p1);
314 pointlist.push_back(dest);
316 degrees.push_back(2);
319 static int intersect_conic(Real x, Real y, Point *p, int /*level*/ = 0)
321 Real ymin,ymax,xmin,xmax;
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]);
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]);
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;
336 //degenerate line max
337 if(ymin == ymax == p[1][1])
340 //degenerate accept - to the right and crossing the base line
343 return (y <= ymax && y >= ymin);
346 //solve for curve = y
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
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],
358 Real t1 = -1, t2 = -1;
363 if(b == 0) return 0; //may not need this check
365 t1 = - c / b; //bt + c = 0 solved
368 //2 degree polynomial
369 Real b2_4ac = b*b - 4*a*c;
371 //if there are double/no roots - no intersections (in real #s that is)
377 b2_4ac = sqrt(b2_4ac);
379 t1 = (-b - b2_4ac) / 2*a,
380 t2 = (-b + b2_4ac) / 2*a;
383 //calculate number of intersections
384 if(t1 >= 0 && t1 <= 1)
387 const Real invt = 1 - t;
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;
395 intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
399 if(t2 >= 0 && t2 <= 1)
402 const Real invt = 1 - t;
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;
410 intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
417 static int quadratic_eqn(Real a, Real b, Real c, Real *t0, Real *t1)
419 const Real b2_4ac = b*b - 4*a*c;
421 //degenerate reject (can't take sqrt)
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);
434 return sqrtb2_4ac == 0 ? 1 : 2;
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)
440 const Real cn[4] = {a,b,c,d};
441 Real p,dp,newt,oldpmag=FLT_MAX;
443 //eval cubic eqn and its derivative
449 for(int i = 2; i < 4; i++)
457 synfig::warning("polish_cubicroot: Derivative should not vanish!!!");
463 if(newt == t || fabs(p) >= oldpmag)
474 static int intersect_cubic(Real x, Real y, Point *p, int /*level*/ = 0)
476 const Real INVALIDROOT = -FLT_MAX;
477 Real ymin,ymax,xmin,xmax;
478 Real ymin2,ymax2,ymintot,ymaxtot;
481 //sort the overall curve ys and xs - degenerate detection
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]);
488 ymin2 = min(p[1][1],p[2][1]);
489 ymax2 = max(p[1][1],p[2][1]);
491 ymintot = min(ymin,ymin2);
492 ymaxtot = max(ymax,ymax2);
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]));
498 //outside all y boundaries (no intersect)
499 if( (y > ymaxtot) || (y < ymintot) ) return 0;
501 //left of curve (no intersect)
502 if(x < xmin) return 0;
504 //right of curve (and outside base range)
507 if( (y > ymax) || (y < ymin) ) return 0;
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];
512 //extract the sign from the value (we need valid data)
513 return n < 0 ? -1 : 1;
516 //degenerate horizontal line max -- doesn't happen enough to check for
517 if( ymintot == ymaxtot ) return 0;
520 // can have 0,1,2, or 3 real roots
521 // if any of them are double then reject the two...
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],
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],
534 Real t1 = INVALIDROOT, t2 = INVALIDROOT, t3 = INVALIDROOT, t, dydt;
544 t1 = - d / c; //equation devolved into: ct + d = 0 - solve...
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;
554 //algorithm courtesy of Numerical Recipes in C (algorithm copied from pg. 184/185)
559 //if cn is 0 (or really really close), then we can simplify this...
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)
567 t1 = t2 = INVALIDROOT;
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;
578 Real theta = acos(R / sqrt(Q*Q*Q));
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;
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;
591 Real signR = R < 0 ? -1 : 1;
592 Real A = - signR * pow(signR*R + sqrt(R*R - Q*Q*Q),1/3.0);
598 //single real root in this case
599 t1 = (A + B) - an/3.0;
604 //if(t1 != INVALIDROOT)
606 t = t1;//polish_cubicroot(a,b,c,d,t1,&dydt);
609 //const Real invt = 1 - t;
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;
617 intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
622 //if(t2 != INVALIDROOT)
624 t = t2;//polish_cubicroot(a,b,c,d,t2,&dydt);
627 //const Real invt = 1 - t;
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;
635 intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
640 //if(t3 != INVALIDROOT)
642 t = t3;//polish_cubicroot(a,b,c,d,t3,&dydt);
645 //const Real invt = 1 - t;
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;
653 intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
661 int intersect(Real x,Real y, Point *table) const
663 if((y < aabb.miny) || (y > aabb.maxy) || (x < aabb.minx)) return 0;
665 int i, curdeg, intersects = 0;
666 const int numcurves = degrees.size();
668 vector<Point>::const_iterator p = pointlist.begin();
670 for(i=0; i < numcurves; i++)
680 table[2] = *p; //we want to include the last point for the next curve
682 intersects += intersect_conic(x,y,table);
692 table[3] = *p; //we want to include the last point for the next curve
694 intersects += intersect_cubic(x,y,table);
701 warning("Invalid degree (%d) inserted into the list (index: %d)\n", curdeg, i);
711 struct Layer_Shape::Intersector
715 //! true iff aabb hasn't been initialised yet
720 enum IntersectorFlags
733 Real close_x,close_y;
735 vector<MonoSegment> segs; //monotonically increasing
736 vector<CurveArray> curves; //big array of consecutive curves
748 return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y);
751 void move_to(Real x, Real y)
758 tangent[0] = tangent[1] = 0;
764 }else aabb.expand(x,y);
769 void line_to(Real x, Real y)
771 int dir = (y > cur_y)*1 + (-1)*(y < cur_y);
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))
777 MonoSegment seg(dir,x,x,y,y);
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));
784 //add to the last segment, because it works
787 segs.back().pointlist.push_back(Point(x,y));
788 segs.back().aabb.expand(x,y);
795 aabb.expand(x,y); //expand the entire thing's bounding box
797 tangent[0] = x - cur_x;
798 tangent[1] = x - cur_y;
804 void conic_to_smooth(Real x, Real y)
806 const Real x1 = tangent[0]/2.0 + cur_x;
807 const Real y1 = tangent[1]/2.0 + cur_y;
812 void conic_to(Real x1, Real y1, Real x, Real y)
814 //if we're not already a curve start one
815 if(prim != TYPE_CURVE)
819 c.Start(Point(cur_x,cur_y));
820 c.AddConic(Point(x1,y1),Point(x,y));
825 curves.back().AddConic(Point(x1,y1),Point(x,y));
834 tangent[0] = 2*(x - x1);
835 tangent[1] = 2*(y - y1);
841 void curve_to_smooth(Real x2, Real y2, Real x, Real y)
843 Real x1 = tangent[0]/3.0 + cur_x;
844 Real y1 = tangent[1]/3.0 + cur_y;
846 curve_to(x1,y1,x2,y2,x,y);
849 void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
851 //if we're not already a curve start one
852 if(prim != TYPE_CURVE)
856 c.Start(Point(cur_x,cur_y));
857 c.AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
862 curves.back().AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
868 //expand bounding box around ALL of it
873 tangent[0] = 3*(x - x2);
874 tangent[1] = 3*(y - y2);
882 if(flags & NotClosed)
884 if(cur_x != close_x || cur_y != close_y)
886 line_to(close_x,close_y);
893 //assumes the line to count the intersections with is (-1,0)
894 int intersect (Real x, Real y) const
898 vector<MonoSegment>::const_iterator s = segs.begin();
899 vector<CurveArray>::const_iterator c = curves.begin();
901 Point memory[3*MAX_SUBDIVISION_SIZE + 1];
903 for(i = 0; i < segs.size(); i++,s++)
905 inter += s->intersect(x,y);
908 for(i=0; i < curves.size(); i++,c++)
909 inter += c->intersect(x,y,memory);
914 //intersect an arbitrary line
915 //int intersect (Real x, Real y, Real vx, Real vy) {return 0;}
923 cur_x = cur_y = close_x = close_y = 0;
925 tangent[0] = tangent[1] = 0;
930 //*********** SCANLINE RENDERER SUPPORT STRUCTURES ***************
937 PenMark(int xin, int yin, Real c, Real a)
938 :y(yin),x(xin),cover(c),area(a) {}
940 void set(int xin, int yin, Real c, Real a) { y = yin; x = xin; cover = c; area = a; }
942 void setcoord(int xin, int yin) { y = yin; x = xin; }
944 void setcover(Real c, Real a) { cover = c; area = a; }
945 void addcover(Real c, Real a) { cover += c; area += a; }
947 bool operator < (const PenMark &rhs) const
949 return y == rhs.y ? x < rhs.x : y < rhs.y;
953 typedef rect<int> ContextRect;
955 class Layer_Shape::PolySpan
958 typedef deque<PenMark> cover_array;
960 Point arc[3*MAX_SUBDIVISION_SIZE + 1];
967 //ending position of last primitive
971 //starting position of current primitive list
975 //flags for the current segment
978 //the window that will be drawn (used for clipping)
981 //for assignment to flags value
988 //default constructor - 0 everything
989 PolySpan() :current(0,0,0,0),flags(NotSorted)
991 cur_x = cur_y = close_x = close_y = 0;
995 bool notclosed() const
997 return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y);
1000 //0 out all the variables involved in processing
1004 cur_x = cur_y = close_x = close_y = 0;
1006 current.set(0,0,0,0);
1010 //add the current cell, but only if there is information to add
1013 if(current.cover || current.area)
1015 covers.push_back(current);
1019 //move to the next cell (cover values 0 initially), keeping the current if necessary
1020 void move_pen(int x, int y)
1022 if(y != current.y || x != current.x)
1025 current.set(x,y,0,0);
1029 //close the primitives with a line (or rendering will not work as expected)
1032 if(flags & NotClosed)
1034 if(cur_x != close_x || cur_y != close_y)
1036 line_to(close_x,close_y);
1038 current.setcover(0,0);
1040 flags &= ~NotClosed;
1044 // Not recommended - destroys any separation of spans currently held
1047 sort(covers.begin(),covers.end());
1051 //will sort the marks if they are not sorted
1054 if(flags & NotSorted)
1056 //only sort the open index
1058 current.setcover(0,0);
1060 sort(covers.begin() + open_index,covers.end());
1061 flags &= ~NotSorted;
1065 //encapsulate the current sublist of marks (used for drawing)
1066 void encapsulate_current()
1068 //sort the current list then reposition the open list section
1070 open_index = covers.size();
1073 //move to start a new primitive list (enclose the last primitive if need be)
1074 void move_to(Real x, Real y)
1079 move_pen((int)floor(x),(int)floor(y));
1080 close_y = cur_y = y;
1081 close_x = cur_x = x;
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);
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);
1092 Real ExtractAlpha(Real area, WindingStyle winding_style)
1097 if (winding_style == WINDING_NON_ZERO)
1099 // non-zero winding style
1103 else // if (winding_style == WINDING_EVEN_ODD)
1105 // even-odd winding style
1109 // want pyramid like thing
1118 /* === M E T H O D S ======================================================= */
1120 Layer_Shape::Layer_Shape(const Real &a, const Color::BlendMethod m):
1121 Layer_Composite (a,m),
1122 edge_table (new Intersector),
1123 color (Color::black()),
1127 blurtype (Blur::FASTGAUSSIAN),
1129 winding_style (WINDING_NON_ZERO),
1131 lastbyteop (Primitive::NONE),
1136 Layer_Shape::~Layer_Shape()
1142 Layer_Shape::clear()
1144 edge_table->clear();
1149 Layer_Shape::set_param(const String & param, const ValueBase &value)
1157 IMPORT(winding_style);
1159 return Layer_Composite::set_param(param,value);
1163 Layer_Shape::get_param(const String ¶m)const
1171 EXPORT(winding_style);
1176 return Layer_Composite::get_param(param);
1180 Layer_Shape::get_param_vocab()const
1182 Layer::Vocab ret(Layer_Composite::get_param_vocab());
1184 ret.push_back(ParamDesc("color")
1185 .set_local_name(_("Color"))
1186 .set_description(_("Layer_Shape Color"))
1188 ret.push_back(ParamDesc("offset")
1189 .set_local_name(_("Position"))
1191 ret.push_back(ParamDesc("invert")
1192 .set_local_name(_("Invert"))
1194 ret.push_back(ParamDesc("antialias")
1195 .set_local_name(_("Antialiasing"))
1197 ret.push_back(ParamDesc("feather")
1198 .set_local_name(_("Feather"))
1201 ret.push_back(ParamDesc("blurtype")
1202 .set_local_name(_("Type of Feather"))
1203 .set_description(_("Type of feathering to use"))
1205 .add_enum_value(Blur::BOX,"box",_("Box Blur"))
1206 .add_enum_value(Blur::FASTGAUSSIAN,"fastgaussian",_("Fast Gaussian Blur"))
1207 .add_enum_value(Blur::CROSS,"cross",_("Cross-Hatch Blur"))
1208 .add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
1209 .add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
1211 ret.push_back(ParamDesc("winding_style")
1212 .set_local_name(_("Winding Style"))
1213 .set_description(_("Winding style to use"))
1215 .add_enum_value(WINDING_NON_ZERO,"nonzero",_("Non Zero"))
1216 .add_enum_value(WINDING_EVEN_ODD,"evenodd",_("Even/Odd"))
1222 synfig::Layer::Handle
1223 Layer_Shape::hit_check(synfig::Context context, const synfig::Point &p)const
1225 Point pos(p-offset);
1227 int intercepts = edge_table->intersect(pos[0],pos[1]);
1229 // If we have an odd number of intercepts, we are inside.
1230 // If we have an even number of intercepts, we are outside.
1231 bool intersect = ((!!intercepts) ^ invert);
1233 if(get_amount() == 0 || get_blend_method() == Color::BLEND_ALPHA_OVER)
1240 synfig::Layer::Handle tmp;
1241 if(get_blend_method()==Color::BLEND_BEHIND && (tmp=context.hit_check(p)))
1243 if(Color::is_onto(get_blend_method()))
1245 //if there's something in the lower layer then we're set...
1246 if(!context.hit_check(p).empty())
1247 return const_cast<Layer_Shape*>(this);
1248 }else if(get_blend_method() == Color::BLEND_ALPHA_OVER)
1250 synfig::info("layer_shape::hit_check - we've got alphaover");
1251 //if there's something in the lower layer then we're set...
1252 if(color.get_a() < 0.1 && get_amount() > .9)
1254 synfig::info("layer_shape::hit_check - can see through us... so nothing");
1256 }else return context.hit_check(p);
1258 return const_cast<Layer_Shape*>(this);
1261 return context.hit_check(p);
1265 Layer_Shape::get_color(Context context, const Point &p)const
1270 pp = Blur(feather,feather,blurtype)(p);
1272 Point pos(pp-offset);
1274 int intercepts = edge_table->intersect(pos[0],pos[1]);
1276 // If we have an odd number of intercepts, we are inside.
1277 // If we have an even number of intercepts, we are outside.
1278 bool intersect = ((!!intercepts) ^ invert);
1281 return context.get_color(pp);
1283 //Ok, we're inside... bummmm ba bum buM...
1284 if(get_blend_method() == Color::BLEND_STRAIGHT && get_amount() == 1)
1287 return Color::blend(color,context.get_color(p),get_amount(),get_blend_method());
1290 //************** SCANLINE RENDERING *********************
1291 void Layer_Shape::PolySpan::line_to(Real x, Real y)
1294 bool afterx = false;
1296 const Real xin(x), yin(y);
1298 Real dx = x - cur_x;
1299 Real dy = y - cur_y;
1303 //outside y - ignore entirely
1304 if( (cur_y >= window.maxy && y >= window.maxy)
1305 ||(cur_y < window.miny && y < window.miny) )
1310 else //not degenerate - more complicated
1312 if(dy > 0) //be sure it's not tooooo small
1314 // cur_y ... window.miny ... window.maxy ... y
1316 //initial degenerate - initial clip
1317 if(cur_y < window.miny)
1319 //new clipped start point (must also move pen)
1320 n[2] = cur_x + (window.miny - cur_y) * dx / dy;
1323 cur_y = window.miny;
1324 move_pen((int)floor(cur_x),window.miny);
1327 //generate data for the ending clipped info
1330 //initial line to intersection (and degenerate)
1331 n[2] = x + (window.maxy - y) * dx / dy;
1340 //initial degenerate - initial clip
1341 if(cur_y > window.maxy)
1343 //new clipped start point (must also move pen)
1344 n[2] = cur_x + (window.maxy - cur_y) * dx / dy;
1347 cur_y = window.maxy;
1348 move_pen((int)floor(cur_x),window.maxy);
1351 //generate data for the ending clipped info
1354 //initial line to intersection (and degenerate)
1355 n[2] = x + (window.miny - y) * dx / dy;
1363 //all degenerate - but require bounded clipped values
1364 if( (cur_x >= window.maxx && x >= window.maxx)
1365 ||(cur_x < window.minx && x < window.minx) )
1367 //clip both vertices - but only needed in the x direction
1368 cur_x = max(cur_x, (Real)window.minx);
1369 cur_x = min(cur_x, (Real)window.maxx);
1371 //clip the dest values - y is already clipped
1372 x = max(x,(Real)window.minx);
1373 x = min(x,(Real)window.maxx);
1375 //must start at new point...
1376 move_pen((int)floor(cur_x),(int)floor(cur_y));
1378 draw_line(cur_x,cur_y,x,y);
1388 //initial degenerate - initial clip
1389 if(cur_x < window.minx)
1391 //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
1392 n[2] = cur_y + (window.minx - cur_x) * dy / dx;
1394 move_pen(window.minx,(int)floor(cur_y));
1395 draw_line(window.minx,cur_y,window.minx,n[2]);
1397 cur_x = window.minx;
1401 //generate data for the ending clipped info
1404 //initial line to intersection (and degenerate)
1405 n[2] = y + (window.maxx - x) * dy / dx;
1417 //initial degenerate - initial clip
1418 if(cur_x > window.maxx)
1420 //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
1421 n[2] = cur_y + (window.maxx - cur_x) * dy / dx;
1423 move_pen(window.maxx,(int)floor(cur_y));
1424 draw_line(window.maxx,cur_y,window.maxx,n[2]);
1426 cur_x = window.maxx;
1430 //generate data for the ending clipped info
1433 //initial line to intersection (and degenerate)
1434 n[2] = y + (window.minx - x) * dy / dx;
1446 move_pen((int)floor(cur_x),(int)floor(cur_y));
1447 //draw the relevant line (clipped)
1448 draw_line(cur_x,cur_y,x,y);
1452 draw_line(x,y,n[0],n[1]);
1459 } catch(...) { synfig::error("line_to: cur_x=%f, cur_y=%f, x=%f, y=%f", cur_x, cur_y, x, y); throw; }
1461 flags |= NotClosed|NotSorted;
1464 static inline bool clip_conic(const Point *const p, const ContextRect &r)
1466 const Real minx = min(min(p[0][0],p[1][0]),p[2][0]);
1467 const Real miny = min(min(p[0][1],p[1][1]),p[2][1]);
1468 const Real maxx = max(max(p[0][0],p[1][0]),p[2][0]);
1469 const Real maxy = max(max(p[0][1],p[1][1]),p[2][1]);
1471 return (minx > r.maxx) ||
1477 static inline bool clip_cubic(const Point *const p, const ContextRect &r)
1479 /*const Real minx = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0]));
1480 const Real miny = min(min(p[0][1],p[1][1]),min(p[2][1],p[3][1]));
1481 const Real maxx = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][1]));
1482 const Real maxy = max(max(p[0][1],p[1][1]),max(p[2][1],p[3][1]));
1484 return (minx > r.maxx) ||
1489 return ((p[0][0] > r.maxx) && (p[1][0] > r.maxx) && (p[2][0] > r.maxx) && (p[3][0] > r.maxx)) ||
1490 ((p[0][0] < r.minx) && (p[1][0] < r.minx) && (p[2][0] < r.minx) && (p[3][0] < r.minx)) ||
1491 ((p[0][1] > r.maxy) && (p[1][1] > r.maxy) && (p[2][1] > r.maxy) && (p[3][1] > r.maxy)) ||
1492 ((p[0][1] < r.miny) && (p[1][1] < r.miny) && (p[2][1] < r.miny) && (p[3][1] < r.miny));
1495 static inline Real max_edges_cubic(const Point *const p)
1497 const Real x1 = p[1][0] - p[0][0];
1498 const Real y1 = p[1][1] - p[0][1];
1500 const Real x2 = p[2][0] - p[1][0];
1501 const Real y2 = p[2][1] - p[1][1];
1503 const Real x3 = p[3][0] - p[2][0];
1504 const Real y3 = p[3][1] - p[2][1];
1506 const Real d1 = x1*x1 + y1*y1;
1507 const Real d2 = x2*x2 + y2*y2;
1508 const Real d3 = x3*x3 + y3*y3;
1510 return max(max(d1,d2),d3);
1513 static inline Real max_edges_conic(const Point *const p)
1515 const Real x1 = p[1][0] - p[0][0];
1516 const Real y1 = p[1][1] - p[0][1];
1518 const Real x2 = p[2][0] - p[1][0];
1519 const Real y2 = p[2][1] - p[1][1];
1521 const Real d1 = x1*x1 + y1*y1;
1522 const Real d2 = x2*x2 + y2*y2;
1527 void Layer_Shape::PolySpan::conic_to(Real x1, Real y1, Real x, Real y)
1529 Point *current = arc;
1532 bool onsecond = false;
1534 arc[0] = Point(x,y);
1535 arc[1] = Point(x1,y1);
1536 arc[2] = Point(cur_x,cur_y);
1538 //just draw the line if it's outside
1539 if(clip_conic(arc,window))
1545 //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
1546 while(current >= arc)
1548 if(num >= MAX_SUBDIVISION_SIZE)
1550 warning("Curve subdivision somehow ran out of space while tesselating!");
1556 //if the curve is clipping then draw degenerate
1557 if(clip_conic(current,window))
1559 line_to(current[0][0],current[0][1]); //backwards so front is destination
1561 if(onsecond) level--;
1566 //if we are not at the level minimum
1567 if(level < MIN_SUBDIVISION_DRAW_LEVELS)
1569 Subd_Conic_Stack(current);
1570 current += 2; //cursor on second curve
1576 //split it again, if it's too big
1577 if(max_edges_conic(current) > 0.25) //distance of .5 (cover no more than half the pixel)
1579 Subd_Conic_Stack(current);
1580 current += 2; //cursor on second curve
1585 else //NOT TOO BIG? RENDER!!!
1587 //cur_x,cur_y = current[2], so we need to go 1,0
1588 line_to(current[1][0],current[1][1]);
1589 line_to(current[0][0],current[0][1]);
1592 if(onsecond) level--;
1599 void Layer_Shape::PolySpan::cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
1601 Point *current = arc;
1604 bool onsecond = false;
1606 arc[0] = Point(x,y);
1607 arc[1] = Point(x2,y2);
1608 arc[2] = Point(x1,y1);
1609 arc[3] = Point(cur_x,cur_y);
1611 //just draw the line if it's outside
1612 if(clip_cubic(arc,window))
1618 //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
1619 while(current >= arc) //once current goes below arc, there are no more curves left
1621 if(num >= MAX_SUBDIVISION_SIZE)
1623 warning("Curve subdivision somehow ran out of space while tesselating!");
1630 //if we are not at the level minimum
1631 if(level < MIN_SUBDIVISION_DRAW_LEVELS)
1633 Subd_Cubic_Stack(current);
1634 current += 3; //cursor on second curve
1640 //if the curve is clipping then draw degenerate
1641 if(clip_cubic(current,window))
1643 line_to(current[0][0],current[0][1]); //backwards so front is destination
1645 if(onsecond) level--;
1651 //split it again, if it's too big
1652 if(max_edges_cubic(current) > 0.25) //could use max_edges<3>
1654 Subd_Cubic_Stack(current);
1655 current += 3; //cursor on second curve
1660 else //NOT TOO BIG? RENDER!!!
1662 //cur_x,cur_y = current[3], so we need to go 2,1,0
1663 line_to(current[2][0],current[2][1]);
1664 line_to(current[1][0],current[1][1]);
1665 line_to(current[0][0],current[0][1]);
1668 if(onsecond) level--;
1675 //******************** LINE ALGORITHMS ****************************
1676 // THESE CALCULATE THE AREA AND THE COVER FOR THE MARKS, TO THEN SCAN CONVERT
1677 // - BROKEN UP INTO SCANLINES (draw_line - y intersections),
1678 // THEN THE COVER AND AREA PER TOUCHED PIXEL IS CALCULATED (draw_scanline - x intersections)
1679 void Layer_Shape::PolySpan::draw_scanline(int y, Real x1, Real fy1, Real x2, Real fy2)
1681 int ix1 = (int)floor(x1);
1682 int ix2 = (int)floor(x2);
1683 Real fx1 = x1 - ix1;
1684 Real fx2 = x2 - ix2;
1686 Real dx,dy,dydx,mult;
1691 //case horizontal line
1694 move_pen(ix2,y); //pen needs to be at the last coord
1698 //case all in same pixel
1699 if(ix1 == ix2) //impossible for degenerate case (covered by the previous cases)
1701 current.addcover(dy,(fx1 + fx2)*dy/2); //horizontal trapazoid area
1707 // ----> fx1...1 0...1 ... 0...1 0...fx2
1710 //set initial values
1711 //Iterate through the covered pixels
1712 mult = (1 - fx1)*dydx; //next y intersection diff value (at 1)
1715 current.addcover(mult,(1 + fx1)*mult/2); // fx1,fy1,1,fy@1 - starting trapazoidal area
1717 //move to the next pixel
1723 //set up for whole ones
1726 //trapezoid(0,y1,1,y1+dydx);
1727 current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
1729 //move to next pixel (+1)
1736 //final y-pos - last intersect pos
1738 current.addcover(mult,(0+fx2)*mult/2);
1741 // fx2...1 0...1 ... 0...1 0...fx1 <----
1742 //mult = (0 - fx1) * dy / dx;
1743 //neg sign sucked into dydx
1746 //set initial values
1747 //Iterate through the covered pixels
1748 mult = fx1*dydx; //next y intersection diff value
1751 current.addcover(mult,fx1*mult/2); // fx1,fy1,0,fy@0 - starting trapazoidal area
1753 //move to next pixel
1759 //set up for whole ones
1762 //trapezoid(0,y1,1,y1+dydx);
1763 current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
1765 //move to next pixel (-1)
1772 mult = fy2 - fy1; //final y-pos - last intersect pos
1774 current.addcover(mult,(fx2+1)*mult/2);
1778 void Layer_Shape::PolySpan::draw_line(Real x1, Real y1, Real x2, Real y2)
1780 int iy1 = (int)floor(y1);
1781 int iy2 = (int)floor(y2);
1782 Real fy1 = y1 - iy1;
1783 Real fy2 = y2 - iy2;
1785 assert(!isnan(fy1));
1786 assert(!isnan(fy2));
1788 Real dx,dy,dxdy,mult,x_from,x_to;
1790 const Real SLOPE_EPSILON = 1e-10;
1792 //case all one scanline
1795 draw_scanline(iy1,x1,y1,x2,y2);
1803 //case vertical line
1804 if(dx < SLOPE_EPSILON && dx > -SLOPE_EPSILON)
1806 //calc area and cover on vertical line
1809 // ----> fx1...1 0...1 ... 0...1 0...fx2
1812 int ix1 = (int)floor(x1);
1813 Real fx1 = x1 - ix1;
1818 current.addcover(sub,fx1*sub);
1823 //move pen to next pixel
1829 current.addcover(1,fx1);
1837 current.addcover(fy2,fy2*fx1);
1842 int ix1 = (int)floor(x1);
1843 Real fx1 = x1 - ix1;
1848 current.addcover(sub,fx1*sub);
1857 //accumulate in current pixel
1858 current.addcover(-1,-fx1);
1865 current.addcover(fy2-1,(fy2-1)*fx1);
1870 //case normal line - guaranteed dx != 0 && dy != 0
1872 //calculate the initial intersection with "next" scanline
1877 mult = (1 - fy1) * dxdy;
1879 //x interset scanline
1881 draw_scanline(iy1,x1,fy1,x_from,1);
1886 move_pen((int)floor(x_from),iy1);
1890 //keep up on the x axis, and render the current scanline
1891 x_to = x_from + dxdy;
1892 draw_scanline(iy1,x_from,0,x_to,1);
1895 //move to next pixel
1897 move_pen((int)floor(x_from),iy1);
1900 //draw the last one, fractional
1901 draw_scanline(iy2,x_from,0,x2,fy2);
1909 //x interset scanline
1911 draw_scanline(iy1,x1,fy1,x_from,0);
1916 move_pen((int)floor(x_from),iy1);
1920 x_to = x_from + dxdy;
1921 draw_scanline(iy1,x_from,1,x_to,0);
1925 move_pen((int)floor(x_from),iy1);
1927 //draw the last one, fractional
1928 draw_scanline(iy2,x_from,1,x2,fy2);
1932 //****** LAYER PEN OPERATIONS (move_to, line_to, etc.) ******
1933 void Layer_Shape::move_to(Real x, Real y)
1935 //const int sizeblock = sizeof(Primitive)+sizeof(Point);
1939 op.operation = Primitive::MOVE_TO;
1940 op.number = 1; //one point for now
1942 if(lastbyteop == Primitive::MOVE_TO)
1944 char *ptr = &bytestream[lastoppos];
1945 memcpy(ptr,&op,sizeof(op));
1946 memcpy(ptr+sizeof(op),&p,sizeof(p));
1948 else //make a new op
1950 lastbyteop = Primitive::MOVE_TO;
1951 lastoppos = bytestream.size();
1953 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
1954 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
1957 edge_table->move_to(x,y);
1960 void Layer_Shape::close()
1964 op.operation = Primitive::CLOSE;
1967 if(lastbyteop == Primitive::CLOSE)
1971 lastbyteop = Primitive::CLOSE;
1972 lastoppos = bytestream.size();
1974 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert header
1977 edge_table->close();
1978 //should not affect the bounding box since it would just be returning to old point...
1981 void Layer_Shape::endpath()
1985 op.operation = Primitive::END;
1988 if(lastbyteop == Primitive::END || lastbyteop == Primitive::NONE)
1992 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));
1994 //should not affect the bounding box since it would just be returning to old point... if at all
1997 void Layer_Shape::line_to(Real x, Real y)
2002 //const int sizeblock = sizeof(Primitive)+sizeof(Point);
2006 op.operation = Primitive::LINE_TO;
2007 op.number = 1; //one point for now
2009 if(lastbyteop == Primitive::MOVE_TO || lastbyteop == Primitive::LINE_TO)
2011 //only need to insert the point
2012 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2014 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2015 prim->number++; //increment number of points in the list
2018 lastbyteop = Primitive::LINE_TO;
2019 lastoppos = bytestream.size();
2021 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2022 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2025 edge_table->line_to(x,y);
2028 void Layer_Shape::conic_to(Real x1, Real y1, Real x, Real y)
2030 //const int sizeblock = sizeof(Primitive)+sizeof(Point)*2;
2035 op.operation = Primitive::CONIC_TO;
2036 op.number = 2; //2 points for now
2038 if(lastbyteop == Primitive::CONIC_TO)
2040 //only need to insert the new points
2041 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
2042 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2044 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2045 prim->number += 2; //increment number of points in the list
2048 lastbyteop = Primitive::CONIC_TO;
2049 lastoppos = bytestream.size();
2051 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2052 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data
2053 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2056 edge_table->conic_to(x1,y1,x,y);
2059 void Layer_Shape::conic_to_smooth(Real x, Real y) //x1,y1 derived from current tangent
2061 //const int sizeblock = sizeof(Primitive)+sizeof(Point);
2065 op.operation = Primitive::CONIC_TO_SMOOTH;
2066 op.number = 1; //2 points for now
2068 if(lastbyteop == Primitive::CONIC_TO_SMOOTH)
2070 //only need to insert the new point
2071 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2073 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2074 prim->number += 1; //increment number of points in the list
2077 lastbyteop = Primitive::CONIC_TO_SMOOTH;
2078 lastoppos = bytestream.size();
2080 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2081 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2084 edge_table->conic_to_smooth(x,y);
2087 void Layer_Shape::curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
2089 //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3;
2095 op.operation = Primitive::CUBIC_TO;
2096 op.number = 3; //3 points for now
2098 if(lastbyteop == Primitive::CUBIC_TO)
2100 //only need to insert the new points
2101 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
2102 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
2103 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2105 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2106 prim->number += 3; //increment number of points in the list
2109 lastbyteop = Primitive::CUBIC_TO;
2110 lastoppos = bytestream.size();
2112 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2113 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data
2114 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data
2115 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2118 edge_table->curve_to(x1,y1,x2,y2,x,y);
2121 void Layer_Shape::curve_to_smooth(Real x2, Real y2, Real x, Real y) //x1,y1 derived from current tangent
2123 //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3;
2128 op.operation = Primitive::CUBIC_TO_SMOOTH;
2129 op.number = 2; //3 points for now
2131 if(lastbyteop == Primitive::CUBIC_TO_SMOOTH)
2133 //only need to insert the new points
2134 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
2135 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2137 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2138 prim->number += 2; //increment number of points in the list
2141 lastbyteop = Primitive::CUBIC_TO_SMOOTH;
2142 lastoppos = bytestream.size();
2144 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2145 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data
2146 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2150 // ACCELERATED RENDER FUNCTION - TRANSLATE BYTE CODE INTO FUNCTION CALLS
2152 bool Layer_Shape::render_polyspan(Surface *surface, PolySpan &polyspan,
2153 Color::BlendMethod got_blend_method, Color::value_type got_amount) const
2155 Surface::alpha_pen p(surface->begin(),got_amount,_BlendFunc(got_blend_method));
2156 PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin();
2157 PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
2159 Real cover,area,alpha;
2166 if(cur_mark == end_mark)
2171 p.move_to(polyspan.window.minx,polyspan.window.miny);
2172 p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx);
2177 //fill initial rect / line
2180 //fill all the area above the first vertex
2181 p.move_to(polyspan.window.minx,polyspan.window.miny);
2182 y = polyspan.window.miny;
2183 int l = polyspan.window.maxx - polyspan.window.minx;
2185 p.put_block(cur_mark->y - polyspan.window.miny,l);
2187 //fill the area to the left of the first vertex on that line
2188 l = cur_mark->x - polyspan.window.minx;
2189 p.move_to(polyspan.window.minx,cur_mark->y);
2190 if(l) p.put_hline(l);
2200 area = cur_mark->area;
2201 cover += cur_mark->cover;
2203 //accumulate for the current pixel
2204 while(++cur_mark != polyspan.covers.end())
2206 if(y != cur_mark->y || x != cur_mark->x)
2209 area += cur_mark->area;
2210 cover += cur_mark->cover;
2213 //draw pixel - based on covered area
2214 if(area) //if we're ok, draw the current pixel
2216 alpha = polyspan.ExtractAlpha(cover - area, winding_style);
2217 if(invert) alpha = 1 - alpha;
2221 if(alpha >= .5) p.put_value();
2223 else if(alpha) p.put_value_alpha(alpha);
2229 //if we're done, don't use iterator and exit
2230 if(cur_mark == end_mark) break;
2232 //if there is no more live pixels on this line, goto next
2233 if(y != cur_mark->y)
2237 //fill the area at the end of the line
2238 p.put_hline(polyspan.window.maxx - x);
2240 //fill area at the beginning of the next line
2241 p.move_to(polyspan.window.minx,cur_mark->y);
2242 p.put_hline(cur_mark->x - polyspan.window.minx);
2250 //draw span to next pixel - based on total amount of pixel cover
2253 alpha = polyspan.ExtractAlpha(cover, winding_style);
2254 if(invert) alpha = 1 - alpha;
2258 if(alpha >= .5) p.put_hline(cur_mark->x - x);
2260 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2264 //fill the after stuff
2267 //fill the area at the end of the line
2268 p.put_hline(polyspan.window.maxx - x);
2270 //fill area at the beginning of the next line
2271 p.move_to(polyspan.window.minx,y+1);
2272 p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
2278 bool Layer_Shape::render_polyspan(etl::surface<float> *surface, PolySpan &polyspan) const
2280 etl::surface<float>::pen p(surface->begin());
2281 PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin();
2282 PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
2284 Real cover,area,alpha;
2290 //the pen always writes 1 (unless told to do otherwise)
2293 if(cur_mark == end_mark)
2298 p.move_to(polyspan.window.minx,polyspan.window.miny);
2299 p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx);
2304 //fill initial rect / line
2307 //fill all the area above the first vertex
2308 p.move_to(polyspan.window.minx,polyspan.window.miny);
2309 y = polyspan.window.miny;
2310 int l = polyspan.window.maxx - polyspan.window.minx;
2312 p.put_block(cur_mark->y - polyspan.window.miny,l);
2314 //fill the area to the left of the first vertex on that line
2315 l = cur_mark->x - polyspan.window.minx;
2316 p.move_to(polyspan.window.minx,cur_mark->y);
2317 if(l) p.put_hline(l);
2326 area = cur_mark->area;
2327 cover += cur_mark->cover;
2329 //accumulate for the current pixel
2330 while(++cur_mark != polyspan.covers.end())
2332 if(y != cur_mark->y || x != cur_mark->x)
2335 area += cur_mark->area;
2336 cover += cur_mark->cover;
2339 //draw pixel - based on covered area
2340 if(area) //if we're ok, draw the current pixel
2342 alpha = 1 - polyspan.ExtractAlpha(cover - area, winding_style);
2345 if(alpha >= .5) p.put_value();
2347 else if(alpha) p.put_value(alpha);
2353 //if we're done, don't use iterator and exit
2354 if(cur_mark == end_mark) break;
2356 //if there is no more live pixels on this line, goto next
2357 if(y != cur_mark->y)
2359 //fill the area at the end of the line
2360 p.put_hline(polyspan.window.maxx - x);
2362 //fill area at the beginning of the next line
2363 p.move_to(polyspan.window.minx,cur_mark->y);
2364 p.put_hline(cur_mark->x - polyspan.window.minx);
2371 //draw span to next pixel - based on total amount of pixel cover
2374 alpha = 1 - polyspan.ExtractAlpha(cover, winding_style);
2377 if(alpha >= .5) p.put_hline(cur_mark->x - x);
2379 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2383 //fill the area at the end of the line
2384 p.put_hline(polyspan.window.maxx - x);
2386 //fill area at the beginning of the next line
2387 p.move_to(polyspan.window.minx,y+1);
2388 p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
2398 area = cur_mark->area;
2399 cover += cur_mark->cover;
2401 //accumulate for the current pixel
2402 while(++cur_mark != polyspan.covers.end())
2404 if(y != cur_mark->y || x != cur_mark->x)
2407 area += cur_mark->area;
2408 cover += cur_mark->cover;
2411 //draw pixel - based on covered area
2412 if(area) //if we're ok, draw the current pixel
2414 alpha = polyspan.ExtractAlpha(cover - area, winding_style);
2417 if(alpha >= .5) p.put_value();
2419 else if(alpha) p.put_value(alpha);
2425 //if we're done, don't use iterator and exit
2426 if(cur_mark == end_mark) break;
2428 //if there is no more live pixels on this line, goto next
2429 if(y != cur_mark->y)
2436 //draw span to next pixel - based on total amount of pixel cover
2439 alpha = polyspan.ExtractAlpha(cover, winding_style);
2442 if(alpha >= .5) p.put_hline(cur_mark->x - x);
2444 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2453 Layer_Shape::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
2455 const unsigned int w = renddesc.get_w();
2456 const unsigned int h = renddesc.get_h();
2458 const Real pw = abs(renddesc.get_pw());
2459 const Real ph = abs(renddesc.get_ph());
2461 //const Real OFFSET_EPSILON = 1e-8;
2462 SuperCallback stageone(cb,1,10000,15001+renddesc.get_h());
2463 SuperCallback stagetwo(cb,10000,10001+renddesc.get_h(),15001+renddesc.get_h());
2464 SuperCallback stagethree(cb,10001+renddesc.get_h(),15001+renddesc.get_h(),15001+renddesc.get_h());
2466 // Render what is behind us
2468 //clip if it satisfies the invert solid thing
2469 if(is_solid_color() && invert)
2471 Rect aabb = edge_table->aabb;
2472 Point tl = renddesc.get_tl() - offset;
2474 Real pw = renddesc.get_pw(),
2475 ph = renddesc.get_ph();
2479 Real pixelfeatherx = abs(feather/pw),
2480 pixelfeathery = abs(feather/ph);
2482 nrect.set_point((aabb.minx - tl[0])/pw,(aabb.miny - tl[1])/ph);
2483 nrect.expand((aabb.maxx - tl[0])/pw,(aabb.maxy - tl[1])/ph);
2485 RendDesc optdesc(renddesc);
2487 //make sure to expand so we gain subpixels rather than lose them
2488 nrect.minx = floor(nrect.minx-pixelfeatherx); nrect.miny = floor(nrect.miny-pixelfeathery);
2489 nrect.maxx = ceil(nrect.maxx+pixelfeatherx); nrect.maxy = ceil(nrect.maxy+pixelfeathery);
2491 //make sure the subwindow is clipped with our tile window (minimize useless drawing)
2492 set_intersect(nrect,nrect,Rect(0,0,renddesc.get_w(),renddesc.get_h()));
2494 //must resize the surface first
2495 surface->set_wh(renddesc.get_w(),renddesc.get_h());
2498 //only render anything if it's visible from our current tile
2501 //set the subwindow to the viewable pixels and render it to the subsurface
2502 optdesc.set_subwindow((int)nrect.minx, (int)nrect.miny,
2503 (int)(nrect.maxx - nrect.minx), (int)(nrect.maxy - nrect.miny));
2505 Surface optimizedbacksurf;
2506 if(!context.accelerated_render(&optimizedbacksurf,quality,optdesc,&stageone))
2509 //blit that onto the original surface so we can pretend that nothing ever happened
2510 Surface::pen p = surface->get_pen((int)nrect.minx,(int)nrect.miny);
2511 optimizedbacksurf.blit_to(p);
2515 if(!context.accelerated_render(surface,quality,renddesc,&stageone))
2519 if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
2523 //we have to blur rather than be crappy
2525 //so make a separate surface
2526 RendDesc workdesc(renddesc);
2528 etl::surface<float> shapesurface;
2530 //the expanded size = 1/2 the size in each direction rounded up
2531 int halfsizex = (int) (abs(feather*.5/pw) + 3),
2532 halfsizey = (int) (abs(feather*.5/ph) + 3);
2534 //expand by 1/2 size in each direction on either side
2541 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey));
2544 case Blur::FASTGAUSSIAN:
2551 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey));
2554 case Blur::GAUSSIAN:
2556 #define GAUSSIAN_ADJUSTMENT (0.05)
2557 Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
2558 Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
2563 halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5);
2564 halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5);
2566 halfsizex = (halfsizex + 1)/2;
2567 halfsizey = (halfsizey + 1)/2;
2568 workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey );
2574 shapesurface.set_wh(workdesc.get_w(),workdesc.get_h());
2575 shapesurface.clear();
2578 if(!render_shape(&shapesurface,quality,workdesc,&stagetwo))return false;
2581 Blur(feather,feather,blurtype,&stagethree)(shapesurface,workdesc.get_br()-workdesc.get_tl(),shapesurface);
2583 //blend with stuff below it...
2584 unsigned int u = halfsizex, v = halfsizey, x = 0, y = 0;
2585 for(y = 0; y < h; y++,v++)
2588 for(x = 0; x < w; x++,u++)
2590 float a = shapesurface[v][u];
2593 //a = floor(a*255+0.5f)/255;
2594 (*surface)[y][x]=Color::blend(color,(*surface)[y][x],a*get_amount(),get_blend_method());
2596 //else (*surface)[y][x] = worksurface[v][u];
2601 if(cb && !cb->amount_complete(100,100))
2603 synfig::warning("Layer_Shape: could not set amount complete");
2610 //might take out to reduce code size
2611 return render_shape(surface,true,quality,renddesc,&stagetwo);
2617 Layer_Shape::render_shape(Surface *surface,bool useblend,int /*quality*/,
2618 const RendDesc &renddesc, ProgressCallback *cb)const
2622 SuperCallback progress(cb,0,renddesc.get_h(),renddesc.get_h());
2624 // If our amount is set to zero, no need to render anything
2628 //test new polygon renderer
2630 // Width and Height of a pixel
2631 const int w = renddesc.get_w();
2632 const int h = renddesc.get_h();
2633 const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
2634 const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
2636 const Point tl = renddesc.get_tl();
2638 Vector tangent (0,0);
2642 //optimization for tesselating only inside tiles
2643 span.window.minx = 0;
2644 span.window.miny = 0;
2645 span.window.maxx = w;
2646 span.window.maxy = h;
2648 //pointers for processing the bytestream
2649 const char *current = &bytestream[0];
2650 const char *end = &bytestream[bytestream.size()];
2652 int operation = Primitive::NONE;
2659 Real x,y,x1,y1,x2,y2;
2662 while(current < end)
2668 //get the op code safely
2669 curprim = (Primitive *)current;
2671 //advance past indices
2672 current += sizeof(Primitive);
2675 warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
2679 //get the relevant data
2680 operation = curprim->operation;
2681 number = curprim->number;
2683 if(operation == Primitive::END)
2686 if(operation == Primitive::CLOSE)
2688 if(span.notclosed())
2690 tangent[0] = span.close_x - span.cur_x;
2691 tangent[1] = span.close_y - span.cur_y;
2697 data = (Point*)current;
2698 current += sizeof(Point)*number;
2700 //check data positioning
2703 warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points");
2707 } catch(...) { synfig::error("Layer_Shape::render_shape()1: Caught an exception after %d loops, rethrowing...", tmp); throw; }
2709 //transfer all the data - RLE optimized
2710 for(curnum=0; curnum < number;)
2714 case Primitive::MOVE_TO:
2716 x = data[curnum][0];
2717 x = (x - tl[0] + offset[0])*pw;
2718 y = data[curnum][1];
2719 y = (y - tl[1] + offset[1])*ph;
2730 tangent[0] = x - span.cur_x;
2731 tangent[1] = y - span.cur_y;
2736 curnum++; //only advance one point
2741 case Primitive::LINE_TO:
2743 x = data[curnum][0];
2744 x = (x - tl[0] + offset[0])*pw;
2745 y = data[curnum][1];
2746 y = (y - tl[1] + offset[1])*ph;
2748 tangent[0] = x - span.cur_x;
2749 tangent[1] = y - span.cur_y;
2756 case Primitive::CONIC_TO:
2758 x = data[curnum+1][0];
2759 x = (x - tl[0] + offset[0])*pw;
2760 y = data[curnum+1][1];
2761 y = (y - tl[1] + offset[1])*ph;
2763 x1 = data[curnum][0];
2764 x1 = (x1 - tl[0] + offset[0])*pw;
2765 y1 = data[curnum][1];
2766 y1 = (y1 - tl[1] + offset[1])*ph;
2768 tangent[0] = 2*(x - x1);
2769 tangent[1] = 2*(y - y1);
2771 span.conic_to(x1,y1,x,y);
2776 case Primitive::CONIC_TO_SMOOTH:
2778 x = data[curnum][0];
2779 x = (x - tl[0] + offset[0])*pw;
2780 y = data[curnum][1];
2781 y = (y - tl[1] + offset[1])*ph;
2783 x1 = span.cur_x + tangent[0]/2;
2784 y1 = span.cur_y + tangent[1]/2;
2786 tangent[0] = 2*(x - x1);
2787 tangent[1] = 2*(y - y1);
2789 span.conic_to(x1,y1,x,y);
2795 case Primitive::CUBIC_TO:
2797 x = data[curnum+2][0];
2798 x = (x - tl[0] + offset[0])*pw;
2799 y = data[curnum+2][1];
2800 y = (y - tl[1] + offset[1])*ph;
2802 x2 = data[curnum+1][0];
2803 x2 = (x2 - tl[0] + offset[0])*pw;
2804 y2 = data[curnum+1][1];
2805 y2 = (y2 - tl[1] + offset[1])*ph;
2807 x1 = data[curnum][0];
2808 x1 = (x1 - tl[0] + offset[0])*pw;
2809 y1 = data[curnum][1];
2810 y1 = (y1 - tl[1] + offset[1])*ph;
2812 tangent[0] = 2*(x - x2);
2813 tangent[1] = 2*(y - y2);
2815 span.cubic_to(x1,y1,x2,y2,x,y);
2821 case Primitive::CUBIC_TO_SMOOTH:
2823 x = data[curnum+1][0];
2824 x = (x - tl[0] + offset[0])*pw;
2825 y = data[curnum+1][1];
2826 y = (y - tl[1] + offset[1])*ph;
2828 x2 = data[curnum][0];
2829 x2 = (x2 - tl[0] + offset[0])*pw;
2830 y2 = data[curnum][1];
2831 y2 = (y2 - tl[1] + offset[1])*ph;
2833 x1 = span.cur_x + tangent[0]/3.0;
2834 y1 = span.cur_y + tangent[1]/3.0;
2836 tangent[0] = 2*(x - x2);
2837 tangent[1] = 2*(y - y2);
2839 span.cubic_to(x1,y1,x2,y2,x,y);
2848 //sort the bastards so we can render everything
2851 return render_polyspan(surface, span,
2852 useblend?get_blend_method():Color::BLEND_STRAIGHT,
2853 useblend?get_amount():1.0);
2857 Layer_Shape::render_shape(surface<float> *surface,int /*quality*/,
2858 const RendDesc &renddesc, ProgressCallback */*cb*/)const
2860 // If our amount is set to zero, no need to render anything
2864 //test new polygon renderer
2866 // Width and Height of a pixel
2867 const int w = renddesc.get_w();
2868 const int h = renddesc.get_h();
2869 const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
2870 const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
2872 const Point tl = renddesc.get_tl();
2874 Vector tangent (0,0);
2878 //optimization for tesselating only inside tiles
2879 span.window.minx = 0;
2880 span.window.miny = 0;
2881 span.window.maxx = w;
2882 span.window.maxy = h;
2884 //pointers for processing the bytestream
2885 const char *current = &bytestream[0];
2886 const char *end = &bytestream[bytestream.size()];
2888 int operation = Primitive::NONE;
2895 Real x,y,x1,y1,x2,y2;
2897 while(current < end)
2899 //get the op code safely
2900 curprim = (Primitive *)current;
2902 //advance past indices
2903 current += sizeof(Primitive);
2906 warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
2910 //get the relevant data
2911 operation = curprim->operation;
2912 number = curprim->number;
2914 if(operation == Primitive::END)
2917 if(operation == Primitive::CLOSE)
2919 if(span.notclosed())
2921 tangent[0] = span.close_x - span.cur_x;
2922 tangent[1] = span.close_y - span.cur_y;
2928 data = (Point*)current;
2929 current += sizeof(Point)*number;
2931 //check data positioning
2934 warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points");
2938 //transfer all the data
2939 for(curnum=0; curnum < number;)
2943 case Primitive::MOVE_TO:
2945 x = data[curnum][0];
2946 x = (x - tl[0] + offset[0])*pw;
2947 y = data[curnum][1];
2948 y = (y - tl[1] + offset[1])*ph;
2959 tangent[0] = x - span.cur_x;
2960 tangent[1] = y - span.cur_y;
2965 curnum++; //only advance one point
2970 case Primitive::LINE_TO:
2972 x = data[curnum][0];
2973 x = (x - tl[0] + offset[0])*pw;
2974 y = data[curnum][1];
2975 y = (y - tl[1] + offset[1])*ph;
2977 tangent[0] = x - span.cur_x;
2978 tangent[1] = y - span.cur_y;
2985 case Primitive::CONIC_TO:
2987 x = data[curnum+1][0];
2988 x = (x - tl[0] + offset[0])*pw;
2989 y = data[curnum+1][1];
2990 y = (y - tl[1] + offset[1])*ph;
2992 x1 = data[curnum][0];
2993 x1 = (x1 - tl[0] + offset[0])*pw;
2994 y1 = data[curnum][1];
2995 y1 = (y1 - tl[1] + offset[1])*ph;
2997 tangent[0] = 2*(x - x1);
2998 tangent[1] = 2*(y - y1);
3000 span.conic_to(x1,y1,x,y);
3005 case Primitive::CONIC_TO_SMOOTH:
3007 x = data[curnum][0];
3008 x = (x - tl[0] + offset[0])*pw;
3009 y = data[curnum][1];
3010 y = (y - tl[1] + offset[1])*ph;
3012 x1 = span.cur_x + tangent[0]/2;
3013 y1 = span.cur_y + tangent[1]/2;
3015 tangent[0] = 2*(x - x1);
3016 tangent[1] = 2*(y - y1);
3018 span.conic_to(x1,y1,x,y);
3024 case Primitive::CUBIC_TO:
3026 x = data[curnum+2][0];
3027 x = (x - tl[0] + offset[0])*pw;
3028 y = data[curnum+2][1];
3029 y = (y - tl[1] + offset[1])*ph;
3031 x2 = data[curnum+1][0];
3032 x2 = (x2 - tl[0] + offset[0])*pw;
3033 y2 = data[curnum+1][1];
3034 y2 = (y2 - tl[1] + offset[1])*ph;
3036 x1 = data[curnum][0];
3037 x1 = (x1 - tl[0] + offset[0])*pw;
3038 y1 = data[curnum][1];
3039 y1 = (y1 - tl[1] + offset[1])*ph;
3041 tangent[0] = 2*(x - x2);
3042 tangent[1] = 2*(y - y2);
3044 span.cubic_to(x1,y1,x2,y2,x,y);
3050 case Primitive::CUBIC_TO_SMOOTH:
3052 x = data[curnum+1][0];
3053 x = (x - tl[0] + offset[0])*pw;
3054 y = data[curnum+1][1];
3055 y = (y - tl[1] + offset[1])*ph;
3057 x2 = data[curnum][0];
3058 x2 = (x2 - tl[0] + offset[0])*pw;
3059 y2 = data[curnum][1];
3060 y2 = (y2 - tl[1] + offset[1])*ph;
3062 x1 = span.cur_x + tangent[0]/3.0;
3063 y1 = span.cur_y + tangent[1]/3.0;
3065 tangent[0] = 2*(x - x2);
3066 tangent[1] = 2*(y - y2);
3068 span.cubic_to(x1,y1,x2,y2,x,y);
3077 //sort the bastards so we can render everything
3080 return render_polyspan(surface, span);
3084 Layer_Shape::get_bounding_rect()const
3087 return Rect::full_plane();
3089 if (edge_table->initaabb)
3090 return Rect::zero();
3092 Rect bounds(edge_table->aabb+offset);
3093 bounds.expand(max((bounds.get_min() - bounds.get_max()).mag()*0.01,