1 /* === S Y N F I G ========================================================= */
2 /*! \file layer_shape.cpp
3 ** \brief Implementation of the "Shape" layer
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include "layer_shape.h"
37 #include "paramdesc.h"
41 #include "valuenode.h"
45 #include "curve_helper.h"
53 /* === U S I N G =========================================================== */
55 using namespace synfig;
59 /* === G L O B A L S ======================================================= */
61 SYNFIG_LAYER_INIT(Layer_Shape);
62 SYNFIG_LAYER_SET_NAME(Layer_Shape,"shape");
63 SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Shape,N_("Shape"));
64 SYNFIG_LAYER_SET_CATEGORY(Layer_Shape,N_("Internal"));
65 SYNFIG_LAYER_SET_VERSION(Layer_Shape,"0.1");
66 SYNFIG_LAYER_SET_CVS_ID(Layer_Shape,"$Id$");
71 inline bool IsZero(const T &n)
73 return (n < EPSILON) && (n > -EPSILON);
76 /* === C L A S S E S ======================================================= */
78 //Assumes 64 byte aligned structures if at all
89 MOVE_TO = 0, //(x,y)+ after first point treated as line_to
90 CLOSE, // NOT RUNLENGTH enabled
91 LINE_TO, //(x,y)+ continuous func
92 CONIC_TO, //(x1,y1,x,y)+ " "
93 CONIC_TO_SMOOTH, //(x,y)+ " "
94 CUBIC_TO, //(x1,y1,x2,y2,x,y)+ " "
95 CUBIC_TO_SMOOTH, //(x2,y2,x,y)+ " "
100 //******** CURVE FUNCTIONS *****************
101 const int MAX_SUBDIVISION_SIZE = 64;
102 const int MIN_SUBDIVISION_DRAW_LEVELS = 4;
104 static void Subd_Conic_Stack(Point *arc)
122 arc[4][0] = arc[2][0];
125 a = arc[1][0] = (arc[0][0] + b)/2;
126 b = arc[3][0] = (arc[4][0] + b)/2;
127 arc[2][0] = (a + b)/2;
130 arc[4][1] = arc[2][1];
133 a = arc[1][1] = (arc[0][1] + b)/2;
134 b = arc[3][1] = (arc[4][1] + b)/2;
135 arc[2][1] = (a + b)/2;
141 arc[3] = (arc[2] + arc[1])/2;
142 arc[1] = (arc[0] + arc[1])/2;
144 arc[2] = (arc[1] + arc[3])/2;
150 static void Subd_Cubic_Stack(Point *arc)
159 * 1+2 b * 0+3*1+3*2+3
165 0.1 2.3 -> 0.1 2 3 4 5.6
169 arc[6][0] = arc[3][0];
174 a = arc[1][0] = (arc[0][0] + b)/2;
176 c = arc[5][0] = (arc[6][0] + c)/2;
178 a = arc[2][0] = (a + b)/2;
179 b = arc[4][0] = (b + c)/2;
181 arc[3][0] = (a + b)/2;
184 arc[6][1] = arc[3][1];
189 a = arc[1][1] = (arc[0][1] + b)/2;
191 c = arc[5][1] = (arc[6][1] + c)/2;
193 a = arc[2][1] = (a + b)/2;
194 b = arc[4][1] = (b + c)/2;
196 arc[3][1] = (a + b)/2;
203 //backwards to avoid overwriting
204 arc[5] = (arc[2] + arc[3])/2;
205 temp = (arc[1] + arc[2])/2;
206 arc[1] = (arc[0] + arc[1])/2;
208 arc[4] = (temp + arc[5])/2;
209 arc[2] = (arc[1] + temp)/2;
211 arc[3] = (arc[2] + arc[4])/2;
216 //************** PARAMETRIC RENDERER SUPPORT STRUCTURES ****************
223 vector<Point> pointlist;
225 MonoSegment(int dir = 0, Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
235 int intersect(Real x,Real y) const
237 if((y < aabb.miny+EPSILON) || (y > aabb.maxy) || (x < aabb.minx)) return 0;
238 if(x > aabb.maxx) return ydir;
241 //int size = pointlist.size();
242 //vector<Point>::const_iterator end = pointlist.end();
243 vector<Point>::const_iterator p = pointlist.begin();
245 //assumes that the rect culled away anything that would be beyond the edges
257 //for the loop to break there must have been a slope (straight line would do nothing)
258 //vector<Point>::const_iterator p1 = p-1;
259 Real dy = p[-1][1] - p[0][1];
260 Real dx = p[-1][0] - p[0][0];
264 Real xi = p[0][0] + (y - p[0][1]) * dx / dy;
265 return (x > xi)*ydir;
271 Rect aabb; //not necessarily as effective - can only reject values
272 vector<Point> pointlist; //run length - p0, p1, p2, p3 = p10, p11, p12, p13 = p20 ...
273 vector<char> degrees;
275 CurveArray(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
277 aabb.set(x0,y0,x1,y1);
280 void reset(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
282 aabb.set(x0,y0,x1,y1);
289 return degrees.size();
294 reset(m[0],m[0],m[1],m[1]);
295 pointlist.push_back(m);
298 void AddCubic(Point p1, Point p2, Point dest)
300 aabb.expand(p1[0],p1[1]);
301 aabb.expand(p2[0],p2[1]);
302 aabb.expand(dest[0],dest[1]);
304 pointlist.push_back(p1);
305 pointlist.push_back(p2);
306 pointlist.push_back(dest);
308 degrees.push_back(3);
311 void AddConic(Point p1, Point dest)
313 aabb.expand(p1[0],p1[1]);
314 aabb.expand(dest[0],dest[1]);
316 pointlist.push_back(p1);
317 pointlist.push_back(dest);
319 degrees.push_back(2);
322 static int intersect_conic(Real x, Real y, Point *p, int /*level*/ = 0)
324 Real ymin,ymax,xmin,xmax;
327 //sort the overall curve ys - degenerate detection
328 ymin = min(p[0][1],p[2][1]);
329 ymax = max(p[0][1],p[2][1]);
331 xmin = min(min(p[0][0],p[1][0]),p[2][0]);
332 xmax = max(max(p[0][0],p[1][0]),p[2][0]);
334 //to the left, to the right and out of range y, or completely out of range y
335 if( x < xmin ) return 0;
336 if( x > xmax && (y > ymax || y < ymin) ) return 0;
337 if( (y > ymax && y > p[1][1]) || (y < ymin && y < p[1][1]) ) return 0;
339 //degenerate line max
340 if(ymin == ymax && ymax == p[1][1])
343 //degenerate accept - to the right and crossing the base line
346 return (y <= ymax && y >= ymin);
349 //solve for curve = y
352 //0 roots - 0 intersection
353 //1 root - get x, and figure out x
354 //2 roots (non-double root) - get 2 xs, and count xs to the left
356 //for conic we can assume 1 intersection for monotonic curve
357 Real a = p[2][1] - 2*p[1][1] + p[0][1],
358 b = 2*p[1][1] - 2*p[0][1],
361 Real t1 = -1, t2 = -1;
366 if(b == 0) return 0; //may not need this check
368 t1 = - c / b; //bt + c = 0 solved
371 //2 degree polynomial
372 Real b2_4ac = b*b - 4*a*c;
374 //if there are double/no roots - no intersections (in real #s that is)
380 b2_4ac = sqrt(b2_4ac);
382 t1 = (-b - b2_4ac) / 2*a,
383 t2 = (-b + b2_4ac) / 2*a;
386 //calculate number of intersections
387 if(t1 >= 0 && t1 <= 1)
390 const Real invt = 1 - t;
392 //find x val and it counts if it's to the left of the point
393 const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0];
394 const Real dy_t = 2*a*t + b;
398 intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
402 if(t2 >= 0 && t2 <= 1)
405 const Real invt = 1 - t;
407 //find x val and it counts if it's to the left of the point
408 const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0];
409 const Real dy_t = 2*a*t + b;
413 intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
420 static int quadratic_eqn(Real a, Real b, Real c, Real *t0, Real *t1)
422 const Real b2_4ac = b*b - 4*a*c;
424 //degenerate reject (can't take sqrt)
430 const Real sqrtb2_4ac = sqrt(b2_4ac);
431 const Real signb = b < 0 ? -1 : 1;
432 const Real q = - 0.5 * (b + signb * sqrtb2_4ac);
437 return sqrtb2_4ac == 0 ? 1 : 2;
440 //Newton-Raphson root polishing (we don't care about bounds, assumes very near the desired root)
441 static Real polish_cubicroot(Real a, Real b, Real c, Real d, Real t, Real *dpdt)
443 const Real cn[4] = {a,b,c,d};
444 Real p,dp,newt,oldpmag=FLT_MAX;
446 //eval cubic eqn and its derivative
452 for(int i = 2; i < 4; i++)
460 synfig::warning("polish_cubicroot: Derivative should not vanish!!!");
466 if(newt == t || fabs(p) >= oldpmag)
477 static int intersect_cubic(Real x, Real y, Point *p, int /*level*/ = 0)
479 const Real INVALIDROOT = -FLT_MAX;
480 Real ymin,ymax,xmin,xmax;
481 Real ymin2,ymax2,ymintot,ymaxtot;
484 //sort the overall curve ys and xs - degenerate detection
486 //open span for the two end points
487 ymin = min(p[0][1],p[3][1]);
488 ymax = max(p[0][1],p[3][1]);
491 ymin2 = min(p[1][1],p[2][1]);
492 ymax2 = max(p[1][1],p[2][1]);
494 ymintot = min(ymin,ymin2);
495 ymaxtot = max(ymax,ymax2);
497 //the entire curve control polygon is in this x range
498 xmin = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0]));
499 xmax = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][0]));
501 //outside all y boundaries (no intersect)
502 if( (y > ymaxtot) || (y < ymintot) ) return 0;
504 //left of curve (no intersect)
505 if(x < xmin) return 0;
507 //right of curve (and outside base range)
510 if( (y > ymax) || (y < ymin) ) return 0;
512 //degenerate accept - to the right and inside the [ymin,ymax] range (already rejected if out of range)
513 const Real n = p[3][1] - p[0][1];
515 //extract the sign from the value (we need valid data)
516 return n < 0 ? -1 : 1;
519 //degenerate horizontal line max -- doesn't happen enough to check for
520 if( ymintot == ymaxtot ) return 0;
523 // can have 0,1,2, or 3 real roots
524 // if any of them are double then reject the two...
526 // y-coefficients for f_y(t) - y = 0
527 Real a = p[3][1] - 3*p[2][1] + 3*p[1][1] - p[0][1],
528 b = 3*p[2][1] - 6*p[1][1] + 3*p[0][1],
529 c = 3*p[1][1] - 3*p[0][1],
532 Real ax = p[3][0] - 3*p[2][0] + 3*p[1][0] - p[0][0],
533 bx = 3*p[2][0] - 6*p[1][0] + 3*p[0][0],
534 cx = 3*p[1][0] - 3*p[0][0],
537 Real t1 = INVALIDROOT, t2 = INVALIDROOT, t3 = INVALIDROOT, t, dydt;
547 t1 = - d / c; //equation devolved into: ct + d = 0 - solve...
550 //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective)
551 if(quadratic_eqn(a,b,c,&t1,&t2) != 2) return 0;
557 //algorithm courtesy of Numerical Recipes in C (algorithm copied from pg. 184/185)
562 //if cn is 0 (or really really close), then we can simplify this...
567 //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective)
568 if(quadratic_eqn(a,b,c,&t1,&t2) != 2)
570 t1 = t2 = INVALIDROOT;
575 //otherwise run the normal cubic root equation
576 Real Q = (an*an - 3.0*bn) / 9.0;
577 Real R = ((2.0*an*an - 9.0*bn)*an + 27.0*cn)/54.0;
581 Real theta = acos(R / sqrt(Q*Q*Q));
583 t1 = -2.0*sqrt(Q)*cos(theta/3) - an/3.0;
584 t2 = -2.0*sqrt(Q)*cos((theta+2*PI)/3.0) - an/3.0;
585 t3 = -2.0*sqrt(Q)*cos((theta-2*PI)/3.0) - an/3.0;
587 //don't need to reorder,l just need to eliminate double/triple roots
588 //if(t3 == t2 && t1 == t2) t2 = t3 = INVALIDROOT;
589 if(t3 == t2) t2 = t3 = INVALIDROOT;
590 if(t1 == t2) t1 = t2 = INVALIDROOT;
591 if(t1 == t3) t1 = t3 = INVALIDROOT;
594 Real signR = R < 0 ? -1 : 1;
595 Real A = - signR * pow(signR*R + sqrt(R*R - Q*Q*Q),1/3.0);
601 //single real root in this case
602 t1 = (A + B) - an/3.0;
607 //if(t1 != INVALIDROOT)
609 t = t1;//polish_cubicroot(a,b,c,d,t1,&dydt);
612 //const Real invt = 1 - t;
614 //find x val and it counts if it's to the left of the point
615 const Real xi = ((ax*t + bx)*t + cx)*t + dx;
616 dydt = (3*a*t + 2*b)*t + c;
620 intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
625 //if(t2 != INVALIDROOT)
627 t = t2;//polish_cubicroot(a,b,c,d,t2,&dydt);
630 //const Real invt = 1 - t;
632 //find x val and it counts if it's to the left of the point
633 const Real xi = ((ax*t + bx)*t + cx)*t + dx;
634 dydt = (3*a*t + 2*b)*t + c;
638 intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
643 //if(t3 != INVALIDROOT)
645 t = t3;//polish_cubicroot(a,b,c,d,t3,&dydt);
648 //const Real invt = 1 - t;
650 //find x val and it counts if it's to the left of the point
651 const Real xi = ((ax*t + bx)*t + cx)*t + dx;
652 dydt = (3*a*t + 2*b)*t + c;
656 intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
664 int intersect(Real x,Real y, Point *table) const
666 if((y < aabb.miny) || (y > aabb.maxy) || (x < aabb.minx)) return 0;
668 int i, curdeg, intersects = 0;
669 const int numcurves = degrees.size();
671 vector<Point>::const_iterator p = pointlist.begin();
673 for(i=0; i < numcurves; i++)
683 table[2] = *p; //we want to include the last point for the next curve
685 intersects += intersect_conic(x,y,table);
695 table[3] = *p; //we want to include the last point for the next curve
697 intersects += intersect_cubic(x,y,table);
704 warning("Invalid degree (%d) inserted into the list (index: %d)\n", curdeg, i);
714 struct Layer_Shape::Intersector
718 //! true iff aabb hasn't been initialized yet
723 enum IntersectorFlags
736 Real close_x,close_y;
738 vector<MonoSegment> segs; //monotonically increasing
739 vector<CurveArray> curves; //big array of consecutive curves
751 return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y);
754 void move_to(Real x, Real y)
761 tangent[0] = tangent[1] = 0;
767 }else aabb.expand(x,y);
772 void line_to(Real x, Real y)
774 int dir = (y > cur_y)*1 + (-1)*(y < cur_y);
776 //check for context (if not line start a new segment)
777 //if we're not in line mode (covers 0 set case), or if directions are different (not valid for 0 direction)
778 if(prim != TYPE_LINE || (dir && segs.back().ydir != dir))
780 MonoSegment seg(dir,x,x,y,y);
782 seg.aabb.expand(cur_x,cur_y);
783 seg.pointlist.push_back(Point(cur_x,cur_y));
784 seg.pointlist.push_back(Point(x,y));
787 //add to the last segment, because it works
790 segs.back().pointlist.push_back(Point(x,y));
791 segs.back().aabb.expand(x,y);
798 aabb.expand(x,y); //expand the entire thing's bounding box
800 tangent[0] = x - cur_x;
801 tangent[1] = x - cur_y;
807 void conic_to_smooth(Real x, Real y)
809 const Real x1 = tangent[0]/2.0 + cur_x;
810 const Real y1 = tangent[1]/2.0 + cur_y;
815 void conic_to(Real x1, Real y1, Real x, Real y)
817 //if we're not already a curve start one
818 if(prim != TYPE_CURVE)
822 c.Start(Point(cur_x,cur_y));
823 c.AddConic(Point(x1,y1),Point(x,y));
828 curves.back().AddConic(Point(x1,y1),Point(x,y));
837 tangent[0] = 2*(x - x1);
838 tangent[1] = 2*(y - y1);
844 void curve_to_smooth(Real x2, Real y2, Real x, Real y)
846 Real x1 = tangent[0]/3.0 + cur_x;
847 Real y1 = tangent[1]/3.0 + cur_y;
849 curve_to(x1,y1,x2,y2,x,y);
852 void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
854 //if we're not already a curve start one
855 if(prim != TYPE_CURVE)
859 c.Start(Point(cur_x,cur_y));
860 c.AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
865 curves.back().AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
871 //expand bounding box around ALL of it
876 tangent[0] = 3*(x - x2);
877 tangent[1] = 3*(y - y2);
885 if(flags & NotClosed)
887 if(cur_x != close_x || cur_y != close_y)
889 line_to(close_x,close_y);
896 //assumes the line to count the intersections with is (-1,0)
897 int intersect (Real x, Real y) const
901 vector<MonoSegment>::const_iterator s = segs.begin();
902 vector<CurveArray>::const_iterator c = curves.begin();
904 Point memory[3*MAX_SUBDIVISION_SIZE + 1];
906 for(i = 0; i < segs.size(); i++,s++)
908 inter += s->intersect(x,y);
911 for(i=0; i < curves.size(); i++,c++)
912 inter += c->intersect(x,y,memory);
917 //intersect an arbitrary line
918 //int intersect (Real x, Real y, Real vx, Real vy) {return 0;}
926 cur_x = cur_y = close_x = close_y = 0;
928 tangent[0] = tangent[1] = 0;
933 //*********** SCANLINE RENDERER SUPPORT STRUCTURES ***************
940 PenMark(int xin, int yin, Real c, Real a)
941 :y(yin),x(xin),cover(c),area(a) {}
943 void set(int xin, int yin, Real c, Real a) { y = yin; x = xin; cover = c; area = a; }
945 void setcoord(int xin, int yin) { y = yin; x = xin; }
947 void setcover(Real c, Real a) { cover = c; area = a; }
948 void addcover(Real c, Real a) { cover += c; area += a; }
950 bool operator<(const PenMark &rhs) const
952 return y == rhs.y ? x < rhs.x : y < rhs.y;
956 typedef rect<int> ContextRect;
958 class Layer_Shape::PolySpan
961 typedef deque<PenMark> cover_array;
963 Point arc[3*MAX_SUBDIVISION_SIZE + 1];
970 //ending position of last primitive
974 //starting position of current primitive list
978 //flags for the current segment
981 //the window that will be drawn (used for clipping)
984 //for assignment to flags value
991 //default constructor - 0 everything
992 PolySpan() :current(0,0,0,0),flags(NotSorted)
994 cur_x = cur_y = close_x = close_y = 0;
998 bool notclosed() const
1000 return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y);
1003 //0 out all the variables involved in processing
1007 cur_x = cur_y = close_x = close_y = 0;
1009 current.set(0,0,0,0);
1013 //add the current cell, but only if there is information to add
1016 if(current.cover || current.area)
1018 covers.push_back(current);
1022 //move to the next cell (cover values 0 initially), keeping the current if necessary
1023 void move_pen(int x, int y)
1025 if(y != current.y || x != current.x)
1028 current.set(x,y,0,0);
1032 //close the primitives with a line (or rendering will not work as expected)
1035 if(flags & NotClosed)
1037 if(cur_x != close_x || cur_y != close_y)
1039 line_to(close_x,close_y);
1041 current.setcover(0,0);
1043 flags &= ~NotClosed;
1047 // Not recommended - destroys any separation of spans currently held
1050 sort(covers.begin(),covers.end());
1054 //will sort the marks if they are not sorted
1057 if(flags & NotSorted)
1059 //only sort the open index
1061 current.setcover(0,0);
1063 sort(covers.begin() + open_index,covers.end());
1064 flags &= ~NotSorted;
1068 //encapsulate the current sublist of marks (used for drawing)
1069 void encapsulate_current()
1071 //sort the current list then reposition the open list section
1073 open_index = covers.size();
1076 //move to start a new primitive list (enclose the last primitive if need be)
1077 void move_to(Real x, Real y)
1082 move_pen((int)floor(x),(int)floor(y));
1083 close_y = cur_y = y;
1084 close_x = cur_x = x;
1087 //primitive_to functions
1088 void line_to(Real x, Real y);
1089 void conic_to(Real x1, Real y1, Real x, Real y);
1090 void cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y);
1092 void draw_scanline(int y, Real x1, Real y1, Real x2, Real y2);
1093 void draw_line(Real x1, Real y1, Real x2, Real y2);
1095 Real ExtractAlpha(Real area, WindingStyle winding_style)
1100 if (winding_style == WINDING_NON_ZERO)
1102 // non-zero winding style
1106 else // if (winding_style == WINDING_EVEN_ODD)
1108 // even-odd winding style
1112 // want pyramid like thing
1121 /* === M E T H O D S ======================================================= */
1123 Layer_Shape::Layer_Shape(const Real &a, const Color::BlendMethod m):
1124 Layer_Composite (a,m),
1125 edge_table (new Intersector),
1126 color (Color::black()),
1130 blurtype (Blur::FASTGAUSSIAN),
1132 winding_style (WINDING_NON_ZERO),
1134 lastbyteop (Primitive::NONE),
1139 Layer_Shape::~Layer_Shape()
1145 Layer_Shape::clear()
1147 edge_table->clear();
1152 Layer_Shape::set_param(const String & param, const ValueBase &value)
1154 IMPORT_PLUS(color, { if (color.get_a() == 0) { if (converted_blend_) {
1155 set_blend_method(Color::BLEND_ALPHA_OVER);
1156 color.set_a(1); } else transparent_color_ = true; } });
1160 IMPORT_PLUS(feather, if(feather<0)feather=0;);
1162 IMPORT(winding_style);
1164 IMPORT_AS(origin,"offset");
1166 return Layer_Composite::set_param(param,value);
1170 Layer_Shape::get_param(const String ¶m)const
1178 EXPORT(winding_style);
1183 return Layer_Composite::get_param(param);
1187 Layer_Shape::get_param_vocab()const
1189 Layer::Vocab ret(Layer_Composite::get_param_vocab());
1191 ret.push_back(ParamDesc("color")
1192 .set_local_name(_("Color"))
1193 .set_description(_("Layer_Shape Color"))
1195 ret.push_back(ParamDesc("origin")
1196 .set_local_name(_("Origin"))
1198 ret.push_back(ParamDesc("invert")
1199 .set_local_name(_("Invert"))
1201 ret.push_back(ParamDesc("antialias")
1202 .set_local_name(_("Antialiasing"))
1204 ret.push_back(ParamDesc("feather")
1205 .set_local_name(_("Feather"))
1208 ret.push_back(ParamDesc("blurtype")
1209 .set_local_name(_("Type of Feather"))
1210 .set_description(_("Type of feathering to use"))
1212 .add_enum_value(Blur::BOX,"box",_("Box Blur"))
1213 .add_enum_value(Blur::FASTGAUSSIAN,"fastgaussian",_("Fast Gaussian Blur"))
1214 .add_enum_value(Blur::CROSS,"cross",_("Cross-Hatch Blur"))
1215 .add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
1216 .add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
1218 ret.push_back(ParamDesc("winding_style")
1219 .set_local_name(_("Winding Style"))
1220 .set_description(_("Winding style to use"))
1222 .add_enum_value(WINDING_NON_ZERO,"nonzero",_("Non Zero"))
1223 .add_enum_value(WINDING_EVEN_ODD,"evenodd",_("Even/Odd"))
1229 synfig::Layer::Handle
1230 Layer_Shape::hit_check(synfig::Context context, const synfig::Point &p)const
1232 Point pos(p-origin);
1234 int intercepts = edge_table->intersect(pos[0],pos[1]);
1236 // If we have an odd number of intercepts, we are inside.
1237 // If we have an even number of intercepts, we are outside.
1238 bool intersect = ((!!intercepts) ^ invert);
1240 if(get_amount() == 0 || get_blend_method() == Color::BLEND_ALPHA_OVER)
1247 synfig::Layer::Handle tmp;
1248 if(get_blend_method()==Color::BLEND_BEHIND && (tmp=context.hit_check(p)))
1250 if(Color::is_onto(get_blend_method()))
1252 //if there's something in the lower layer then we're set...
1253 if(!context.hit_check(p).empty())
1254 return const_cast<Layer_Shape*>(this);
1255 }else if(get_blend_method() == Color::BLEND_ALPHA_OVER)
1257 synfig::info("layer_shape::hit_check - we've got alphaover");
1258 //if there's something in the lower layer then we're set...
1259 if(color.get_a() < 0.1 && get_amount() > .9)
1261 synfig::info("layer_shape::hit_check - can see through us... so nothing");
1263 }else return context.hit_check(p);
1265 return const_cast<Layer_Shape*>(this);
1268 return context.hit_check(p);
1272 Layer_Shape::get_color(Context context, const Point &p)const
1277 pp = Blur(feather,feather,blurtype)(p);
1279 Point pos(pp-origin);
1281 int intercepts = edge_table->intersect(pos[0],pos[1]);
1283 // If we have an odd number of intercepts, we are inside.
1284 // If we have an even number of intercepts, we are outside.
1285 bool intersect = ((!!intercepts) ^ invert);
1288 return context.get_color(pp);
1290 //Ok, we're inside... bummmm ba bum buM...
1291 if(get_blend_method() == Color::BLEND_STRAIGHT && get_amount() == 1)
1294 return Color::blend(color,context.get_color(p),get_amount(),get_blend_method());
1297 //************** SCANLINE RENDERING *********************
1298 void Layer_Shape::PolySpan::line_to(Real x, Real y)
1300 Real n[4] = {0,0,0,0};
1301 bool afterx = false;
1303 const Real xin(x), yin(y);
1305 Real dx = x - cur_x;
1306 Real dy = y - cur_y;
1310 //outside y - ignore entirely
1311 if( (cur_y >= window.maxy && y >= window.maxy)
1312 ||(cur_y < window.miny && y < window.miny) )
1317 else //not degenerate - more complicated
1319 if(dy > 0) //be sure it's not tooooo small
1321 // cur_y ... window.miny ... window.maxy ... y
1323 //initial degenerate - initial clip
1324 if(cur_y < window.miny)
1326 //new clipped start point (must also move pen)
1327 n[2] = cur_x + (window.miny - cur_y) * dx / dy;
1330 cur_y = window.miny;
1331 move_pen((int)floor(cur_x),window.miny);
1334 //generate data for the ending clipped info
1337 //initial line to intersection (and degenerate)
1338 n[2] = x + (window.maxy - y) * dx / dy;
1347 //initial degenerate - initial clip
1348 if(cur_y > window.maxy)
1350 //new clipped start point (must also move pen)
1351 n[2] = cur_x + (window.maxy - cur_y) * dx / dy;
1354 cur_y = window.maxy;
1355 move_pen((int)floor(cur_x),window.maxy);
1358 //generate data for the ending clipped info
1361 //initial line to intersection (and degenerate)
1362 n[2] = x + (window.miny - y) * dx / dy;
1370 //all degenerate - but require bounded clipped values
1371 if( (cur_x >= window.maxx && x >= window.maxx)
1372 ||(cur_x < window.minx && x < window.minx) )
1374 //clip both vertices - but only needed in the x direction
1375 cur_x = max(cur_x, (Real)window.minx);
1376 cur_x = min(cur_x, (Real)window.maxx);
1378 //clip the dest values - y is already clipped
1379 x = max(x,(Real)window.minx);
1380 x = min(x,(Real)window.maxx);
1382 //must start at new point...
1383 move_pen((int)floor(cur_x),(int)floor(cur_y));
1385 draw_line(cur_x,cur_y,x,y);
1395 //initial degenerate - initial clip
1396 if(cur_x < window.minx)
1398 //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
1399 n[2] = cur_y + (window.minx - cur_x) * dy / dx;
1401 move_pen(window.minx,(int)floor(cur_y));
1402 draw_line(window.minx,cur_y,window.minx,n[2]);
1404 cur_x = window.minx;
1408 //generate data for the ending clipped info
1411 //initial line to intersection (and degenerate)
1412 n[2] = y + (window.maxx - x) * dy / dx;
1424 //initial degenerate - initial clip
1425 if(cur_x > window.maxx)
1427 //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
1428 n[2] = cur_y + (window.maxx - cur_x) * dy / dx;
1430 move_pen(window.maxx,(int)floor(cur_y));
1431 draw_line(window.maxx,cur_y,window.maxx,n[2]);
1433 cur_x = window.maxx;
1437 //generate data for the ending clipped info
1440 //initial line to intersection (and degenerate)
1441 n[2] = y + (window.minx - x) * dy / dx;
1453 move_pen((int)floor(cur_x),(int)floor(cur_y));
1454 //draw the relevant line (clipped)
1455 draw_line(cur_x,cur_y,x,y);
1459 draw_line(x,y,n[0],n[1]);
1466 } catch(...) { synfig::error("line_to: cur_x=%f, cur_y=%f, x=%f, y=%f", cur_x, cur_y, x, y); throw; }
1468 flags |= NotClosed|NotSorted;
1471 static inline bool clip_conic(const Point *const p, const ContextRect &r)
1473 const Real minx = min(min(p[0][0],p[1][0]),p[2][0]);
1474 const Real miny = min(min(p[0][1],p[1][1]),p[2][1]);
1475 const Real maxx = max(max(p[0][0],p[1][0]),p[2][0]);
1476 const Real maxy = max(max(p[0][1],p[1][1]),p[2][1]);
1478 return (minx > r.maxx) ||
1484 static inline bool clip_cubic(const Point *const p, const ContextRect &r)
1486 /*const Real minx = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0]));
1487 const Real miny = min(min(p[0][1],p[1][1]),min(p[2][1],p[3][1]));
1488 const Real maxx = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][1]));
1489 const Real maxy = max(max(p[0][1],p[1][1]),max(p[2][1],p[3][1]));
1491 return (minx > r.maxx) ||
1496 return ((p[0][0] > r.maxx) && (p[1][0] > r.maxx) && (p[2][0] > r.maxx) && (p[3][0] > r.maxx)) ||
1497 ((p[0][0] < r.minx) && (p[1][0] < r.minx) && (p[2][0] < r.minx) && (p[3][0] < r.minx)) ||
1498 ((p[0][1] > r.maxy) && (p[1][1] > r.maxy) && (p[2][1] > r.maxy) && (p[3][1] > r.maxy)) ||
1499 ((p[0][1] < r.miny) && (p[1][1] < r.miny) && (p[2][1] < r.miny) && (p[3][1] < r.miny));
1502 static inline Real max_edges_cubic(const Point *const p)
1504 const Real x1 = p[1][0] - p[0][0];
1505 const Real y1 = p[1][1] - p[0][1];
1507 const Real x2 = p[2][0] - p[1][0];
1508 const Real y2 = p[2][1] - p[1][1];
1510 const Real x3 = p[3][0] - p[2][0];
1511 const Real y3 = p[3][1] - p[2][1];
1513 const Real d1 = x1*x1 + y1*y1;
1514 const Real d2 = x2*x2 + y2*y2;
1515 const Real d3 = x3*x3 + y3*y3;
1517 return max(max(d1,d2),d3);
1520 static inline Real max_edges_conic(const Point *const p)
1522 const Real x1 = p[1][0] - p[0][0];
1523 const Real y1 = p[1][1] - p[0][1];
1525 const Real x2 = p[2][0] - p[1][0];
1526 const Real y2 = p[2][1] - p[1][1];
1528 const Real d1 = x1*x1 + y1*y1;
1529 const Real d2 = x2*x2 + y2*y2;
1534 void Layer_Shape::PolySpan::conic_to(Real x1, Real y1, Real x, Real y)
1536 Point *current = arc;
1539 bool onsecond = false;
1541 arc[0] = Point(x,y);
1542 arc[1] = Point(x1,y1);
1543 arc[2] = Point(cur_x,cur_y);
1545 //just draw the line if it's outside
1546 if(clip_conic(arc,window))
1552 //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
1553 while(current >= arc)
1555 if(num >= MAX_SUBDIVISION_SIZE)
1557 warning("Curve subdivision somehow ran out of space while tessellating!");
1563 //if the curve is clipping then draw degenerate
1564 if(clip_conic(current,window))
1566 line_to(current[0][0],current[0][1]); //backwards so front is destination
1568 if(onsecond) level--;
1573 //if we are not at the level minimum
1574 if(level < MIN_SUBDIVISION_DRAW_LEVELS)
1576 Subd_Conic_Stack(current);
1577 current += 2; //cursor on second curve
1583 //split it again, if it's too big
1584 if(max_edges_conic(current) > 0.25) //distance of .5 (cover no more than half the pixel)
1586 Subd_Conic_Stack(current);
1587 current += 2; //cursor on second curve
1592 else //NOT TOO BIG? RENDER!!!
1594 //cur_x,cur_y = current[2], so we need to go 1,0
1595 line_to(current[1][0],current[1][1]);
1596 line_to(current[0][0],current[0][1]);
1599 if(onsecond) level--;
1606 void Layer_Shape::PolySpan::cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
1608 Point *current = arc;
1611 bool onsecond = false;
1613 arc[0] = Point(x,y);
1614 arc[1] = Point(x2,y2);
1615 arc[2] = Point(x1,y1);
1616 arc[3] = Point(cur_x,cur_y);
1618 //just draw the line if it's outside
1619 if(clip_cubic(arc,window))
1625 //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
1626 while(current >= arc) //once current goes below arc, there are no more curves left
1628 if(num >= MAX_SUBDIVISION_SIZE)
1630 warning("Curve subdivision somehow ran out of space while tessellating!");
1637 //if we are not at the level minimum
1638 if(level < MIN_SUBDIVISION_DRAW_LEVELS)
1640 Subd_Cubic_Stack(current);
1641 current += 3; //cursor on second curve
1647 //if the curve is clipping then draw degenerate
1648 if(clip_cubic(current,window))
1650 line_to(current[0][0],current[0][1]); //backwards so front is destination
1652 if(onsecond) level--;
1658 //split it again, if it's too big
1659 if(max_edges_cubic(current) > 0.25) //could use max_edges<3>
1661 Subd_Cubic_Stack(current);
1662 current += 3; //cursor on second curve
1667 else //NOT TOO BIG? RENDER!!!
1669 //cur_x,cur_y = current[3], so we need to go 2,1,0
1670 line_to(current[2][0],current[2][1]);
1671 line_to(current[1][0],current[1][1]);
1672 line_to(current[0][0],current[0][1]);
1675 if(onsecond) level--;
1682 //******************** LINE ALGORITHMS ****************************
1683 // THESE CALCULATE THE AREA AND THE COVER FOR THE MARKS, TO THEN SCAN CONVERT
1684 // - BROKEN UP INTO SCANLINES (draw_line - y intersections),
1685 // THEN THE COVER AND AREA PER TOUCHED PIXEL IS CALCULATED (draw_scanline - x intersections)
1686 void Layer_Shape::PolySpan::draw_scanline(int y, Real x1, Real fy1, Real x2, Real fy2)
1688 int ix1 = (int)floor(x1);
1689 int ix2 = (int)floor(x2);
1690 Real fx1 = x1 - ix1;
1691 Real fx2 = x2 - ix2;
1693 Real dx,dy,dydx,mult;
1698 //case horizontal line
1701 move_pen(ix2,y); //pen needs to be at the last coord
1705 //case all in same pixel
1706 if(ix1 == ix2) //impossible for degenerate case (covered by the previous cases)
1708 current.addcover(dy,(fx1 + fx2)*dy/2); //horizontal trapezoid area
1714 // ----> fx1...1 0...1 ... 0...1 0...fx2
1717 //set initial values
1718 //Iterate through the covered pixels
1719 mult = (1 - fx1)*dydx; //next y intersection diff value (at 1)
1722 current.addcover(mult,(1 + fx1)*mult/2); // fx1,fy1,1,fy@1 - starting trapezoidal area
1724 //move to the next pixel
1730 //set up for whole ones
1733 //trapezoid(0,y1,1,y1+dydx);
1734 current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
1736 //move to next pixel (+1)
1743 //final y-pos - last intersect pos
1745 current.addcover(mult,(0+fx2)*mult/2);
1748 // fx2...1 0...1 ... 0...1 0...fx1 <----
1749 //mult = (0 - fx1) * dy / dx;
1750 //neg sign sucked into dydx
1753 //set initial values
1754 //Iterate through the covered pixels
1755 mult = fx1*dydx; //next y intersection diff value
1758 current.addcover(mult,fx1*mult/2); // fx1,fy1,0,fy@0 - starting trapezoidal area
1760 //move to next pixel
1766 //set up for whole ones
1769 //trapezoid(0,y1,1,y1+dydx);
1770 current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
1772 //move to next pixel (-1)
1779 mult = fy2 - fy1; //final y-pos - last intersect pos
1781 current.addcover(mult,(fx2+1)*mult/2);
1785 void Layer_Shape::PolySpan::draw_line(Real x1, Real y1, Real x2, Real y2)
1787 int iy1 = (int)floor(y1);
1788 int iy2 = (int)floor(y2);
1789 Real fy1 = y1 - iy1;
1790 Real fy2 = y2 - iy2;
1792 assert(!isnan(fy1));
1793 assert(!isnan(fy2));
1795 Real dx,dy,dxdy,mult,x_from,x_to;
1797 const Real SLOPE_EPSILON = 1e-10;
1799 //case all one scanline
1802 draw_scanline(iy1,x1,y1,x2,y2);
1810 //case vertical line
1811 if(dx < SLOPE_EPSILON && dx > -SLOPE_EPSILON)
1813 //calc area and cover on vertical line
1816 // ----> fx1...1 0...1 ... 0...1 0...fx2
1819 int ix1 = (int)floor(x1);
1820 Real fx1 = x1 - ix1;
1825 current.addcover(sub,fx1*sub);
1830 //move pen to next pixel
1836 current.addcover(1,fx1);
1844 current.addcover(fy2,fy2*fx1);
1849 int ix1 = (int)floor(x1);
1850 Real fx1 = x1 - ix1;
1855 current.addcover(sub,fx1*sub);
1864 //accumulate in current pixel
1865 current.addcover(-1,-fx1);
1872 current.addcover(fy2-1,(fy2-1)*fx1);
1877 //case normal line - guaranteed dx != 0 && dy != 0
1879 //calculate the initial intersection with "next" scanline
1884 mult = (1 - fy1) * dxdy;
1886 //x intersect scanline
1888 draw_scanline(iy1,x1,fy1,x_from,1);
1893 move_pen((int)floor(x_from),iy1);
1897 //keep up on the x axis, and render the current scanline
1898 x_to = x_from + dxdy;
1899 draw_scanline(iy1,x_from,0,x_to,1);
1902 //move to next pixel
1904 move_pen((int)floor(x_from),iy1);
1907 //draw the last one, fractional
1908 draw_scanline(iy2,x_from,0,x2,fy2);
1916 //x intersect scanline
1918 draw_scanline(iy1,x1,fy1,x_from,0);
1923 move_pen((int)floor(x_from),iy1);
1927 x_to = x_from + dxdy;
1928 draw_scanline(iy1,x_from,1,x_to,0);
1932 move_pen((int)floor(x_from),iy1);
1934 //draw the last one, fractional
1935 draw_scanline(iy2,x_from,1,x2,fy2);
1939 //****** LAYER PEN OPERATIONS (move_to, line_to, etc.) ******
1940 void Layer_Shape::move_to(Real x, Real y)
1942 //const int sizeblock = sizeof(Primitive)+sizeof(Point);
1946 op.operation = Primitive::MOVE_TO;
1947 op.number = 1; //one point for now
1949 if(lastbyteop == Primitive::MOVE_TO)
1951 char *ptr = &bytestream[lastoppos];
1952 memcpy(ptr,&op,sizeof(op));
1953 memcpy(ptr+sizeof(op),&p,sizeof(p));
1955 else //make a new op
1957 lastbyteop = Primitive::MOVE_TO;
1958 lastoppos = bytestream.size();
1960 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
1961 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
1964 edge_table->move_to(x,y);
1967 void Layer_Shape::close()
1971 op.operation = Primitive::CLOSE;
1974 if(lastbyteop == Primitive::CLOSE)
1978 lastbyteop = Primitive::CLOSE;
1979 lastoppos = bytestream.size();
1981 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert header
1984 edge_table->close();
1985 //should not affect the bounding box since it would just be returning to old point...
1988 void Layer_Shape::endpath()
1992 op.operation = Primitive::END;
1995 if(lastbyteop == Primitive::END || lastbyteop == Primitive::NONE)
1999 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1));
2001 //should not affect the bounding box since it would just be returning to old point... if at all
2004 void Layer_Shape::line_to(Real x, Real y)
2009 //const int sizeblock = sizeof(Primitive)+sizeof(Point);
2013 op.operation = Primitive::LINE_TO;
2014 op.number = 1; //one point for now
2016 if(lastbyteop == Primitive::MOVE_TO || lastbyteop == Primitive::LINE_TO)
2018 //only need to insert the point
2019 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2021 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2022 prim->number++; //increment number of points in the list
2025 lastbyteop = Primitive::LINE_TO;
2026 lastoppos = bytestream.size();
2028 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2029 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2032 edge_table->line_to(x,y);
2035 void Layer_Shape::conic_to(Real x1, Real y1, Real x, Real y)
2037 //const int sizeblock = sizeof(Primitive)+sizeof(Point)*2;
2042 op.operation = Primitive::CONIC_TO;
2043 op.number = 2; //2 points for now
2045 if(lastbyteop == Primitive::CONIC_TO)
2047 //only need to insert the new points
2048 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
2049 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2051 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2052 prim->number += 2; //increment number of points in the list
2055 lastbyteop = Primitive::CONIC_TO;
2056 lastoppos = bytestream.size();
2058 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2059 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data
2060 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2063 edge_table->conic_to(x1,y1,x,y);
2066 void Layer_Shape::conic_to_smooth(Real x, Real y) //x1,y1 derived from current tangent
2068 //const int sizeblock = sizeof(Primitive)+sizeof(Point);
2072 op.operation = Primitive::CONIC_TO_SMOOTH;
2073 op.number = 1; //2 points for now
2075 if(lastbyteop == Primitive::CONIC_TO_SMOOTH)
2077 //only need to insert the new point
2078 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2080 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2081 prim->number += 1; //increment number of points in the list
2084 lastbyteop = Primitive::CONIC_TO_SMOOTH;
2085 lastoppos = bytestream.size();
2087 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2088 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2091 edge_table->conic_to_smooth(x,y);
2094 void Layer_Shape::curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
2096 //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3;
2102 op.operation = Primitive::CUBIC_TO;
2103 op.number = 3; //3 points for now
2105 if(lastbyteop == Primitive::CUBIC_TO)
2107 //only need to insert the new points
2108 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
2109 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
2110 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2112 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2113 prim->number += 3; //increment number of points in the list
2116 lastbyteop = Primitive::CUBIC_TO;
2117 lastoppos = bytestream.size();
2119 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2120 bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data
2121 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data
2122 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2125 edge_table->curve_to(x1,y1,x2,y2,x,y);
2128 void Layer_Shape::curve_to_smooth(Real x2, Real y2, Real x, Real y) //x1,y1 derived from current tangent
2130 //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3;
2135 op.operation = Primitive::CUBIC_TO_SMOOTH;
2136 op.number = 2; //3 points for now
2138 if(lastbyteop == Primitive::CUBIC_TO_SMOOTH)
2140 //only need to insert the new points
2141 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
2142 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
2144 Primitive * prim = (Primitive *)&bytestream[lastoppos];
2145 prim->number += 2; //increment number of points in the list
2148 lastbyteop = Primitive::CUBIC_TO_SMOOTH;
2149 lastoppos = bytestream.size();
2151 bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
2152 bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data
2153 bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
2157 // ACCELERATED RENDER FUNCTION - TRANSLATE BYTE CODE INTO FUNCTION CALLS
2159 bool Layer_Shape::render_polyspan(Surface *surface, PolySpan &polyspan,
2160 Color::BlendMethod got_blend_method, Color::value_type got_amount) const
2162 Surface::alpha_pen p(surface->begin(),got_amount,_BlendFunc(got_blend_method));
2163 PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin();
2164 PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
2166 Real cover,area,alpha;
2173 if(cur_mark == end_mark)
2178 p.move_to(polyspan.window.minx,polyspan.window.miny);
2179 p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx);
2184 //fill initial rect / line
2187 //fill all the area above the first vertex
2188 p.move_to(polyspan.window.minx,polyspan.window.miny);
2189 y = polyspan.window.miny;
2190 int l = polyspan.window.maxx - polyspan.window.minx;
2192 p.put_block(cur_mark->y - polyspan.window.miny,l);
2194 //fill the area to the left of the first vertex on that line
2195 l = cur_mark->x - polyspan.window.minx;
2196 p.move_to(polyspan.window.minx,cur_mark->y);
2197 if(l) p.put_hline(l);
2207 area = cur_mark->area;
2208 cover += cur_mark->cover;
2210 //accumulate for the current pixel
2211 while(++cur_mark != polyspan.covers.end())
2213 if(y != cur_mark->y || x != cur_mark->x)
2216 area += cur_mark->area;
2217 cover += cur_mark->cover;
2220 //draw pixel - based on covered area
2221 if(area) //if we're ok, draw the current pixel
2223 alpha = polyspan.ExtractAlpha(cover - area, winding_style);
2224 if(invert) alpha = 1 - alpha;
2228 if(alpha >= .5) p.put_value();
2230 else if(alpha) p.put_value_alpha(alpha);
2236 //if we're done, don't use iterator and exit
2237 if(cur_mark == end_mark) break;
2239 //if there is no more live pixels on this line, goto next
2240 if(y != cur_mark->y)
2244 //fill the area at the end of the line
2245 p.put_hline(polyspan.window.maxx - x);
2247 //fill area at the beginning of the next line
2248 p.move_to(polyspan.window.minx,cur_mark->y);
2249 p.put_hline(cur_mark->x - polyspan.window.minx);
2257 //draw span to next pixel - based on total amount of pixel cover
2260 alpha = polyspan.ExtractAlpha(cover, winding_style);
2261 if(invert) alpha = 1 - alpha;
2265 if(alpha >= .5) p.put_hline(cur_mark->x - x);
2267 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2271 //fill the after stuff
2274 //fill the area at the end of the line
2275 p.put_hline(polyspan.window.maxx - x);
2277 //fill area at the beginning of the next line
2278 p.move_to(polyspan.window.minx,y+1);
2279 p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
2285 bool Layer_Shape::render_polyspan(etl::surface<float> *surface, PolySpan &polyspan) const
2287 etl::surface<float>::pen p(surface->begin());
2288 PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin();
2289 PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
2291 Real cover,area,alpha;
2297 //the pen always writes 1 (unless told to do otherwise)
2300 if(cur_mark == end_mark)
2305 p.move_to(polyspan.window.minx,polyspan.window.miny);
2306 p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx);
2311 //fill initial rect / line
2314 //fill all the area above the first vertex
2315 p.move_to(polyspan.window.minx,polyspan.window.miny);
2316 y = polyspan.window.miny;
2317 int l = polyspan.window.maxx - polyspan.window.minx;
2319 p.put_block(cur_mark->y - polyspan.window.miny,l);
2321 //fill the area to the left of the first vertex on that line
2322 l = cur_mark->x - polyspan.window.minx;
2323 p.move_to(polyspan.window.minx,cur_mark->y);
2324 if(l) p.put_hline(l);
2333 area = cur_mark->area;
2334 cover += cur_mark->cover;
2336 //accumulate for the current pixel
2337 while(++cur_mark != polyspan.covers.end())
2339 if(y != cur_mark->y || x != cur_mark->x)
2342 area += cur_mark->area;
2343 cover += cur_mark->cover;
2346 //draw pixel - based on covered area
2347 if(area) //if we're ok, draw the current pixel
2349 alpha = 1 - polyspan.ExtractAlpha(cover - area, winding_style);
2352 if(alpha >= .5) p.put_value();
2354 else if(alpha) p.put_value(alpha);
2360 //if we're done, don't use iterator and exit
2361 if(cur_mark == end_mark) break;
2363 //if there is no more live pixels on this line, goto next
2364 if(y != cur_mark->y)
2366 //fill the area at the end of the line
2367 p.put_hline(polyspan.window.maxx - x);
2369 //fill area at the beginning of the next line
2370 p.move_to(polyspan.window.minx,cur_mark->y);
2371 p.put_hline(cur_mark->x - polyspan.window.minx);
2378 //draw span to next pixel - based on total amount of pixel cover
2381 alpha = 1 - polyspan.ExtractAlpha(cover, winding_style);
2384 if(alpha >= .5) p.put_hline(cur_mark->x - x);
2386 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2390 //fill the area at the end of the line
2391 p.put_hline(polyspan.window.maxx - x);
2393 //fill area at the beginning of the next line
2394 p.move_to(polyspan.window.minx,y+1);
2395 p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
2405 area = cur_mark->area;
2406 cover += cur_mark->cover;
2408 //accumulate for the current pixel
2409 while(++cur_mark != polyspan.covers.end())
2411 if(y != cur_mark->y || x != cur_mark->x)
2414 area += cur_mark->area;
2415 cover += cur_mark->cover;
2418 //draw pixel - based on covered area
2419 if(area) //if we're ok, draw the current pixel
2421 alpha = polyspan.ExtractAlpha(cover - area, winding_style);
2424 if(alpha >= .5) p.put_value();
2426 else if(alpha) p.put_value(alpha);
2432 //if we're done, don't use iterator and exit
2433 if(cur_mark == end_mark) break;
2435 //if there is no more live pixels on this line, goto next
2436 if(y != cur_mark->y)
2443 //draw span to next pixel - based on total amount of pixel cover
2446 alpha = polyspan.ExtractAlpha(cover, winding_style);
2449 if(alpha >= .5) p.put_hline(cur_mark->x - x);
2451 else if(alpha) p.put_hline(cur_mark->x - x,alpha);
2460 Layer_Shape::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
2462 const unsigned int w = renddesc.get_w();
2463 const unsigned int h = renddesc.get_h();
2465 const Real pw = abs(renddesc.get_pw());
2466 const Real ph = abs(renddesc.get_ph());
2468 //const Real OFFSET_EPSILON = 1e-8;
2469 SuperCallback stageone(cb,1,10000,15001+renddesc.get_h());
2470 SuperCallback stagetwo(cb,10000,10001+renddesc.get_h(),15001+renddesc.get_h());
2471 SuperCallback stagethree(cb,10001+renddesc.get_h(),15001+renddesc.get_h(),15001+renddesc.get_h());
2473 // Render what is behind us
2475 //clip if it satisfies the invert solid thing
2476 if(is_solid_color() && invert)
2478 Rect aabb = edge_table->aabb;
2479 Point tl = renddesc.get_tl() - origin;
2481 Real pw = renddesc.get_pw(),
2482 ph = renddesc.get_ph();
2486 Real pixelfeatherx = quality == 10 ? 0 : abs(feather/pw),
2487 pixelfeathery = quality == 10 ? 0 : abs(feather/ph);
2489 nrect.set_point((aabb.minx - tl[0])/pw,(aabb.miny - tl[1])/ph);
2490 nrect.expand((aabb.maxx - tl[0])/pw,(aabb.maxy - tl[1])/ph);
2492 RendDesc optdesc(renddesc);
2494 //make sure to expand so we gain subpixels rather than lose them
2495 nrect.minx = floor(nrect.minx-pixelfeatherx); nrect.miny = floor(nrect.miny-pixelfeathery);
2496 nrect.maxx = ceil(nrect.maxx+pixelfeatherx); nrect.maxy = ceil(nrect.maxy+pixelfeathery);
2498 //make sure the subwindow is clipped with our tile window (minimize useless drawing)
2499 set_intersect(nrect,nrect,Rect(0,0,renddesc.get_w(),renddesc.get_h()));
2501 //must resize the surface first
2502 surface->set_wh(renddesc.get_w(),renddesc.get_h());
2505 //only render anything if it's visible from our current tile
2508 //set the subwindow to the viewable pixels and render it to the subsurface
2509 optdesc.set_subwindow((int)nrect.minx, (int)nrect.miny,
2510 (int)(nrect.maxx - nrect.minx), (int)(nrect.maxy - nrect.miny));
2512 Surface optimizedbacksurf;
2513 if(!context.accelerated_render(&optimizedbacksurf,quality,optdesc,&stageone))
2516 //blit that onto the original surface so we can pretend that nothing ever happened
2517 Surface::pen p = surface->get_pen((int)nrect.minx,(int)nrect.miny);
2518 optimizedbacksurf.blit_to(p);
2522 if(!context.accelerated_render(surface,quality,renddesc,&stageone))
2526 if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
2528 if(feather && quality != 10)
2530 //we have to blur rather than be crappy
2532 //so make a separate surface
2533 RendDesc workdesc(renddesc);
2535 etl::surface<float> shapesurface;
2537 //the expanded size = 1/2 the size in each direction rounded up
2538 int halfsizex = (int) (abs(feather*.5/pw) + 3),
2539 halfsizey = (int) (abs(feather*.5/ph) + 3);
2541 //expand by 1/2 size in each direction on either side
2548 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey));
2551 case Blur::FASTGAUSSIAN:
2558 workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey));
2561 case Blur::GAUSSIAN:
2563 #define GAUSSIAN_ADJUSTMENT (0.05)
2564 Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
2565 Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
2570 halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5);
2571 halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5);
2573 halfsizex = (halfsizex + 1)/2;
2574 halfsizey = (halfsizey + 1)/2;
2575 workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey );
2581 shapesurface.set_wh(workdesc.get_w(),workdesc.get_h());
2582 shapesurface.clear();
2585 if(!render_shape(&shapesurface,quality,workdesc,&stagetwo))return false;
2588 Blur(feather,feather,blurtype,&stagethree)(shapesurface,workdesc.get_br()-workdesc.get_tl(),shapesurface);
2590 //blend with stuff below it...
2591 unsigned int u = halfsizex, v = halfsizey, x = 0, y = 0;
2592 for(y = 0; y < h; y++,v++)
2595 for(x = 0; x < w; x++,u++)
2597 float a = shapesurface[v][u];
2600 //a = floor(a*255+0.5f)/255;
2601 (*surface)[y][x]=Color::blend(color,(*surface)[y][x],a*get_amount(),get_blend_method());
2603 //else (*surface)[y][x] = worksurface[v][u];
2608 if(cb && !cb->amount_complete(100,100))
2610 synfig::warning("Layer_Shape: could not set amount complete");
2617 //might take out to reduce code size
2618 return render_shape(surface,true,quality,renddesc,&stagetwo);
2624 Layer_Shape::render_shape(Surface *surface,bool useblend,int /*quality*/,
2625 const RendDesc &renddesc, ProgressCallback *cb)const
2629 SuperCallback progress(cb,0,renddesc.get_h(),renddesc.get_h());
2631 // If our amount is set to zero, no need to render anything
2635 //test new polygon renderer
2637 // Width and Height of a pixel
2638 const int w = renddesc.get_w();
2639 const int h = renddesc.get_h();
2640 const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
2641 const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
2643 const Point tl = renddesc.get_tl();
2645 Vector tangent (0,0);
2649 // if the pixels are zero sized then we're too zoomed out to see anything
2650 if (pw == 0 || ph == 0)
2653 //optimization for tessellating only inside tiles
2654 span.window.minx = 0;
2655 span.window.miny = 0;
2656 span.window.maxx = w;
2657 span.window.maxy = h;
2659 //pointers for processing the bytestream
2660 const char *current = &bytestream[0];
2661 const char *end = &bytestream[bytestream.size()];
2663 int operation = Primitive::NONE;
2670 Real x,y,x1,y1,x2,y2;
2673 while(current < end)
2679 //get the op code safely
2680 curprim = (Primitive *)current;
2682 //advance past indices
2683 current += sizeof(Primitive);
2686 warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
2690 //get the relevant data
2691 operation = curprim->operation;
2692 number = curprim->number;
2694 if(operation == Primitive::END)
2697 if(operation == Primitive::CLOSE)
2699 if(span.notclosed())
2701 tangent[0] = span.close_x - span.cur_x;
2702 tangent[1] = span.close_y - span.cur_y;
2708 data = (Point*)current;
2709 current += sizeof(Point)*number;
2711 //check data positioning
2714 warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points");
2718 } catch(...) { synfig::error("Layer_Shape::render_shape()1: Caught an exception after %d loops, rethrowing...", tmp); throw; }
2720 //transfer all the data - RLE optimized
2721 for(curnum=0; curnum < number;)
2725 case Primitive::MOVE_TO:
2727 x = data[curnum][0];
2728 x = (x - tl[0] + origin[0])*pw;
2729 y = data[curnum][1];
2730 y = (y - tl[1] + origin[1])*ph;
2741 tangent[0] = x - span.cur_x;
2742 tangent[1] = y - span.cur_y;
2747 curnum++; //only advance one point
2752 case Primitive::LINE_TO:
2754 x = data[curnum][0];
2755 x = (x - tl[0] + origin[0])*pw;
2756 y = data[curnum][1];
2757 y = (y - tl[1] + origin[1])*ph;
2759 tangent[0] = x - span.cur_x;
2760 tangent[1] = y - span.cur_y;
2767 case Primitive::CONIC_TO:
2769 x = data[curnum+1][0];
2770 x = (x - tl[0] + origin[0])*pw;
2771 y = data[curnum+1][1];
2772 y = (y - tl[1] + origin[1])*ph;
2774 x1 = data[curnum][0];
2775 x1 = (x1 - tl[0] + origin[0])*pw;
2776 y1 = data[curnum][1];
2777 y1 = (y1 - tl[1] + origin[1])*ph;
2779 tangent[0] = 2*(x - x1);
2780 tangent[1] = 2*(y - y1);
2782 span.conic_to(x1,y1,x,y);
2787 case Primitive::CONIC_TO_SMOOTH:
2789 x = data[curnum][0];
2790 x = (x - tl[0] + origin[0])*pw;
2791 y = data[curnum][1];
2792 y = (y - tl[1] + origin[1])*ph;
2794 x1 = span.cur_x + tangent[0]/2;
2795 y1 = span.cur_y + tangent[1]/2;
2797 tangent[0] = 2*(x - x1);
2798 tangent[1] = 2*(y - y1);
2800 span.conic_to(x1,y1,x,y);
2806 case Primitive::CUBIC_TO:
2808 x = data[curnum+2][0];
2809 x = (x - tl[0] + origin[0])*pw;
2810 y = data[curnum+2][1];
2811 y = (y - tl[1] + origin[1])*ph;
2813 x2 = data[curnum+1][0];
2814 x2 = (x2 - tl[0] + origin[0])*pw;
2815 y2 = data[curnum+1][1];
2816 y2 = (y2 - tl[1] + origin[1])*ph;
2818 x1 = data[curnum][0];
2819 x1 = (x1 - tl[0] + origin[0])*pw;
2820 y1 = data[curnum][1];
2821 y1 = (y1 - tl[1] + origin[1])*ph;
2823 tangent[0] = 2*(x - x2);
2824 tangent[1] = 2*(y - y2);
2826 span.cubic_to(x1,y1,x2,y2,x,y);
2832 case Primitive::CUBIC_TO_SMOOTH:
2834 x = data[curnum+1][0];
2835 x = (x - tl[0] + origin[0])*pw;
2836 y = data[curnum+1][1];
2837 y = (y - tl[1] + origin[1])*ph;
2839 x2 = data[curnum][0];
2840 x2 = (x2 - tl[0] + origin[0])*pw;
2841 y2 = data[curnum][1];
2842 y2 = (y2 - tl[1] + origin[1])*ph;
2844 x1 = span.cur_x + tangent[0]/3.0;
2845 y1 = span.cur_y + tangent[1]/3.0;
2847 tangent[0] = 2*(x - x2);
2848 tangent[1] = 2*(y - y2);
2850 span.cubic_to(x1,y1,x2,y2,x,y);
2859 //sort the bastards so we can render everything
2862 return render_polyspan(surface, span,
2863 useblend?get_blend_method():Color::BLEND_STRAIGHT,
2864 useblend?get_amount():1.0);
2868 Layer_Shape::render_shape(etl::surface<float> *surface,int /*quality*/,
2869 const RendDesc &renddesc, ProgressCallback */*cb*/)const
2871 // If our amount is set to zero, no need to render anything
2875 //test new polygon renderer
2877 // Width and Height of a pixel
2878 const int w = renddesc.get_w();
2879 const int h = renddesc.get_h();
2880 const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
2881 const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
2883 const Point tl = renddesc.get_tl();
2885 Vector tangent (0,0);
2889 //optimization for tessellating only inside tiles
2890 span.window.minx = 0;
2891 span.window.miny = 0;
2892 span.window.maxx = w;
2893 span.window.maxy = h;
2895 //pointers for processing the bytestream
2896 const char *current = &bytestream[0];
2897 const char *end = &bytestream[bytestream.size()];
2899 int operation = Primitive::NONE;
2906 Real x,y,x1,y1,x2,y2;
2908 while(current < end)
2910 //get the op code safely
2911 curprim = (Primitive *)current;
2913 //advance past indices
2914 current += sizeof(Primitive);
2917 warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
2921 //get the relevant data
2922 operation = curprim->operation;
2923 number = curprim->number;
2925 if(operation == Primitive::END)
2928 if(operation == Primitive::CLOSE)
2930 if(span.notclosed())
2932 tangent[0] = span.close_x - span.cur_x;
2933 tangent[1] = span.close_y - span.cur_y;
2939 data = (Point*)current;
2940 current += sizeof(Point)*number;
2942 //check data positioning
2945 warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points");
2949 //transfer all the data
2950 for(curnum=0; curnum < number;)
2954 case Primitive::MOVE_TO:
2956 x = data[curnum][0];
2957 x = (x - tl[0] + origin[0])*pw;
2958 y = data[curnum][1];
2959 y = (y - tl[1] + origin[1])*ph;
2970 tangent[0] = x - span.cur_x;
2971 tangent[1] = y - span.cur_y;
2976 curnum++; //only advance one point
2981 case Primitive::LINE_TO:
2983 x = data[curnum][0];
2984 x = (x - tl[0] + origin[0])*pw;
2985 y = data[curnum][1];
2986 y = (y - tl[1] + origin[1])*ph;
2988 tangent[0] = x - span.cur_x;
2989 tangent[1] = y - span.cur_y;
2996 case Primitive::CONIC_TO:
2998 x = data[curnum+1][0];
2999 x = (x - tl[0] + origin[0])*pw;
3000 y = data[curnum+1][1];
3001 y = (y - tl[1] + origin[1])*ph;
3003 x1 = data[curnum][0];
3004 x1 = (x1 - tl[0] + origin[0])*pw;
3005 y1 = data[curnum][1];
3006 y1 = (y1 - tl[1] + origin[1])*ph;
3008 tangent[0] = 2*(x - x1);
3009 tangent[1] = 2*(y - y1);
3011 span.conic_to(x1,y1,x,y);
3016 case Primitive::CONIC_TO_SMOOTH:
3018 x = data[curnum][0];
3019 x = (x - tl[0] + origin[0])*pw;
3020 y = data[curnum][1];
3021 y = (y - tl[1] + origin[1])*ph;
3023 x1 = span.cur_x + tangent[0]/2;
3024 y1 = span.cur_y + tangent[1]/2;
3026 tangent[0] = 2*(x - x1);
3027 tangent[1] = 2*(y - y1);
3029 span.conic_to(x1,y1,x,y);
3035 case Primitive::CUBIC_TO:
3037 x = data[curnum+2][0];
3038 x = (x - tl[0] + origin[0])*pw;
3039 y = data[curnum+2][1];
3040 y = (y - tl[1] + origin[1])*ph;
3042 x2 = data[curnum+1][0];
3043 x2 = (x2 - tl[0] + origin[0])*pw;
3044 y2 = data[curnum+1][1];
3045 y2 = (y2 - tl[1] + origin[1])*ph;
3047 x1 = data[curnum][0];
3048 x1 = (x1 - tl[0] + origin[0])*pw;
3049 y1 = data[curnum][1];
3050 y1 = (y1 - tl[1] + origin[1])*ph;
3052 tangent[0] = 2*(x - x2);
3053 tangent[1] = 2*(y - y2);
3055 span.cubic_to(x1,y1,x2,y2,x,y);
3061 case Primitive::CUBIC_TO_SMOOTH:
3063 x = data[curnum+1][0];
3064 x = (x - tl[0] + origin[0])*pw;
3065 y = data[curnum+1][1];
3066 y = (y - tl[1] + origin[1])*ph;
3068 x2 = data[curnum][0];
3069 x2 = (x2 - tl[0] + origin[0])*pw;
3070 y2 = data[curnum][1];
3071 y2 = (y2 - tl[1] + origin[1])*ph;
3073 x1 = span.cur_x + tangent[0]/3.0;
3074 y1 = span.cur_y + tangent[1]/3.0;
3076 tangent[0] = 2*(x - x2);
3077 tangent[1] = 2*(y - y2);
3079 span.cubic_to(x1,y1,x2,y2,x,y);
3088 //sort the bastards so we can render everything
3091 return render_polyspan(surface, span);
3095 Layer_Shape::get_bounding_rect()const
3098 return Rect::full_plane();
3100 if (edge_table->initaabb)
3101 return Rect::zero();
3103 Rect bounds(edge_table->aabb+origin);
3104 bounds.expand(max((bounds.get_min() - bounds.get_max()).mag()*0.01,