/* === S Y N F I G ========================================================= */
/*! \file layer_shape.cpp
-** \brief Template Header
+** \brief Implementation of the "Shape" layer
**
** $Id$
**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** Copyright (c) 2007, 2008 Chris Moore
**
** This package is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License as
SYNFIG_LAYER_INIT(Layer_Shape);
SYNFIG_LAYER_SET_NAME(Layer_Shape,"shape");
-SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Shape,_("Shape"));
-SYNFIG_LAYER_SET_CATEGORY(Layer_Shape,_("Internal"));
+SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Shape,N_("Shape"));
+SYNFIG_LAYER_SET_CATEGORY(Layer_Shape,N_("Internal"));
SYNFIG_LAYER_SET_VERSION(Layer_Shape,"0.1");
SYNFIG_LAYER_SET_CVS_ID(Layer_Shape,"$Id$");
int intersect(Real x,Real y) const
{
- if((y < aabb.miny) || (y > aabb.maxy) || (x < aabb.minx)) return 0;
+ if((y < aabb.miny+EPSILON) || (y > aabb.maxy) || (x < aabb.minx)) return 0;
if(x > aabb.maxx) return ydir;
//int i = 0;
//assumes that the rect culled away anything that would be beyond the edges
if(ydir > 0)
{
- while(y > (*++p)[1]);
+ while(y > (*++p)[1])
+ ;
}
else
{
- while(y < (*++p)[1]);
+ while(y < (*++p)[1])
+ ;
}
//for the loop to break there must have been a slope (straight line would do nothing)
degrees.push_back(2);
}
- static int intersect_conic(Real x, Real y, Point *p, int level = 0)
+ static int intersect_conic(Real x, Real y, Point *p, int /*level*/ = 0)
{
Real ymin,ymax,xmin,xmax;
int intersects = 0;
if( (y > ymax && y > p[1][1]) || (y < ymin && y < p[1][1]) ) return 0;
//degenerate line max
- if(ymin == ymax == p[1][1])
+ if(ymin == ymax && ymax == p[1][1])
return 0;
//degenerate accept - to the right and crossing the base line
const Real cn[4] = {a,b,c,d};
Real p,dp,newt,oldpmag=FLT_MAX;
- //eval cubic eqn and it's derivative
+ //eval cubic eqn and its derivative
for(;;)
{
p = cn[0]*t + cn[1];
}
}
- static int intersect_cubic(Real x, Real y, Point *p, int level = 0)
+ static int intersect_cubic(Real x, Real y, Point *p, int /*level*/ = 0)
{
const Real INVALIDROOT = -FLT_MAX;
Real ymin,ymax,xmin,xmax;
{
Rect aabb;
- //! true iff aabb hasn't been initialised yet
+ //! true iff aabb hasn't been initialized yet
bool initaabb;
int flags;
void setcover(Real c, Real a) { cover = c; area = a; }
void addcover(Real c, Real a) { cover += c; area += a; }
- bool operator < (const PenMark &rhs) const
+ bool operator<(const PenMark &rhs) const
{
return y == rhs.y ? x < rhs.x : y < rhs.y;
}
void draw_scanline(int y, Real x1, Real y1, Real x2, Real y2);
void draw_line(Real x1, Real y1, Real x2, Real y2);
- Real ExtractAlpha(Real area)
+ Real ExtractAlpha(Real area, WindingStyle winding_style)
{
- //non-zero winding style
- if(area < 0) area = -area;
- if(area > 1) area = 1;
+ if (area < 0)
+ area = -area;
- //even-odd winding style
- /*if(area < 0) area = -area;
+ if (winding_style == WINDING_NON_ZERO)
+ {
+ // non-zero winding style
+ if (area > 1)
+ return 1;
+ }
+ else // if (winding_style == WINDING_EVEN_ODD)
+ {
+ // even-odd winding style
+ while (area > 1)
+ area -= 2;
- while(area > 2) area -= 2;
- if(area > 1) area = 1-area; //want pyramid like thing
- */
- //broken? - yep broken
+ // want pyramid like thing
+ if (area < 0)
+ area = -area;
+ }
return area;
}
Layer_Composite (a,m),
edge_table (new Intersector),
color (Color::black()),
- offset (0,0),
+ origin (0,0),
invert (false),
antialias (true),
blurtype (Blur::FASTGAUSSIAN),
feather (0),
+ winding_style (WINDING_NON_ZERO),
bytestream (0),
lastbyteop (Primitive::NONE),
lastoppos (-1)
bool
Layer_Shape::set_param(const String & param, const ValueBase &value)
{
- IMPORT(color);
- IMPORT(offset);
+ IMPORT_PLUS(color, { if (color.get_a() == 0) { if (converted_blend_) {
+ set_blend_method(Color::BLEND_ALPHA_OVER);
+ color.set_a(1); } else transparent_color_ = true; } });
+ IMPORT(origin);
IMPORT(invert);
IMPORT(antialias);
- IMPORT(feather);
+ IMPORT_PLUS(feather, if(feather<0)feather=0;);
IMPORT(blurtype);
+ IMPORT(winding_style);
+
+ IMPORT_AS(origin,"offset");
return Layer_Composite::set_param(param,value);
}
Layer_Shape::get_param(const String ¶m)const
{
EXPORT(color);
- EXPORT(offset);
+ EXPORT(origin);
EXPORT(invert);
EXPORT(antialias);
EXPORT(feather);
EXPORT(blurtype);
+ EXPORT(winding_style);
EXPORT_NAME();
EXPORT_VERSION();
.set_local_name(_("Color"))
.set_description(_("Layer_Shape Color"))
);
- ret.push_back(ParamDesc("offset")
- .set_local_name(_("Position"))
+ ret.push_back(ParamDesc("origin")
+ .set_local_name(_("Origin"))
);
ret.push_back(ParamDesc("invert")
.set_local_name(_("Invert"))
.add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
.add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
);
+ ret.push_back(ParamDesc("winding_style")
+ .set_local_name(_("Winding Style"))
+ .set_description(_("Winding style to use"))
+ .set_hint("enum")
+ .add_enum_value(WINDING_NON_ZERO,"nonzero",_("Non Zero"))
+ .add_enum_value(WINDING_EVEN_ODD,"evenodd",_("Even/Odd"))
+ );
return ret;
}
synfig::Layer::Handle
Layer_Shape::hit_check(synfig::Context context, const synfig::Point &p)const
{
- Point pos(p-offset);
+ Point pos(p-origin);
int intercepts = edge_table->intersect(pos[0],pos[1]);
if(feather)
pp = Blur(feather,feather,blurtype)(p);
- Point pos(pp-offset);
+ Point pos(pp-origin);
int intercepts = edge_table->intersect(pos[0],pos[1]);
bool intersect = ((!!intercepts) ^ invert);
if(!intersect)
- return context.get_color(pp);
+ return Color::blend(Color::alpha(),context.get_color(pp),get_amount(),get_blend_method());
//Ok, we're inside... bummmm ba bum buM...
if(get_blend_method() == Color::BLEND_STRAIGHT && get_amount() == 1)
//************** SCANLINE RENDERING *********************
void Layer_Shape::PolySpan::line_to(Real x, Real y)
{
- Real n[4];
+ Real n[4] = {0,0,0,0};
bool afterx = false;
const Real xin(x), yin(y);
//generate data for the ending clipped info
if(y > window.maxy)
{
- //intial line to intersection (and degenerate)
+ //initial line to intersection (and degenerate)
n[2] = x + (window.maxy - y) * dx / dy;
//intersect coords
//generate data for the ending clipped info
if(y < window.miny)
{
- //intial line to intersection (and degenerate)
+ //initial line to intersection (and degenerate)
n[2] = x + (window.miny - y) * dx / dy;
//intersect coords
//generate data for the ending clipped info
if(x > window.maxx)
{
- //intial line to intersection (and degenerate)
+ //initial line to intersection (and degenerate)
n[2] = y + (window.maxx - x) * dy / dx;
n[0] = window.maxx;
//generate data for the ending clipped info
if(x < window.minx)
{
- //intial line to intersection (and degenerate)
+ //initial line to intersection (and degenerate)
n[2] = y + (window.minx - x) * dy / dx;
n[0] = window.minx;
{
if(num >= MAX_SUBDIVISION_SIZE)
{
- warning("Curve subdivision somehow ran out of space while tesselating!");
+ warning("Curve subdivision somehow ran out of space while tessellating!");
//do something...
assert(0);
{
if(num >= MAX_SUBDIVISION_SIZE)
{
- warning("Curve subdivision somehow ran out of space while tesselating!");
+ warning("Curve subdivision somehow ran out of space while tessellating!");
//do something...
assert(0);
//case all in same pixel
if(ix1 == ix2) //impossible for degenerate case (covered by the previous cases)
{
- current.addcover(dy,(fx1 + fx2)*dy/2); //horizontal trapazoid area
+ current.addcover(dy,(fx1 + fx2)*dy/2); //horizontal trapezoid area
return;
}
mult = (1 - fx1)*dydx; //next y intersection diff value (at 1)
//first pixel
- current.addcover(mult,(1 + fx1)*mult/2); // fx1,fy1,1,fy@1 - starting trapazoidal area
+ current.addcover(mult,(1 + fx1)*mult/2); // fx1,fy1,1,fy@1 - starting trapezoidal area
//move to the next pixel
fy1 += mult;
mult = fx1*dydx; //next y intersection diff value
//first pixel
- current.addcover(mult,fx1*mult/2); // fx1,fy1,0,fy@0 - starting trapazoidal area
+ current.addcover(mult,fx1*mult/2); // fx1,fy1,0,fy@0 - starting trapezoidal area
//move to next pixel
fy1 += mult;
mult = (1 - fy1) * dxdy;
- //x interset scanline
+ //x intersect scanline
x_from = x1 + mult;
draw_scanline(iy1,x1,fy1,x_from,1);
mult = fy1 * dxdy;
- //x interset scanline
+ //x intersect scanline
x_from = x1 + mult;
draw_scanline(iy1,x1,fy1,x_from,0);
//draw pixel - based on covered area
if(area) //if we're ok, draw the current pixel
{
- alpha = polyspan.ExtractAlpha(cover - area);
+ alpha = polyspan.ExtractAlpha(cover - area, winding_style);
if(invert) alpha = 1 - alpha;
if(!antialias)
//draw span to next pixel - based on total amount of pixel cover
if(x < cur_mark->x)
{
- alpha = polyspan.ExtractAlpha(cover);
+ alpha = polyspan.ExtractAlpha(cover, winding_style);
if(invert) alpha = 1 - alpha;
if(!antialias)
//draw pixel - based on covered area
if(area) //if we're ok, draw the current pixel
{
- alpha = 1 - polyspan.ExtractAlpha(cover - area);
+ alpha = 1 - polyspan.ExtractAlpha(cover - area, winding_style);
if(!antialias)
{
if(alpha >= .5) p.put_value();
//draw span to next pixel - based on total amount of pixel cover
if(x < cur_mark->x)
{
- alpha = 1 - polyspan.ExtractAlpha(cover);
+ alpha = 1 - polyspan.ExtractAlpha(cover, winding_style);
if(!antialias)
{
if(alpha >= .5) p.put_hline(cur_mark->x - x);
//draw pixel - based on covered area
if(area) //if we're ok, draw the current pixel
{
- alpha = polyspan.ExtractAlpha(cover - area);
+ alpha = polyspan.ExtractAlpha(cover - area, winding_style);
if(!antialias)
{
if(alpha >= .5) p.put_value();
//draw span to next pixel - based on total amount of pixel cover
if(x < cur_mark->x)
{
- alpha = polyspan.ExtractAlpha(cover);
+ alpha = polyspan.ExtractAlpha(cover, winding_style);
if(!antialias)
{
if(alpha >= .5) p.put_hline(cur_mark->x - x);
if(is_solid_color() && invert)
{
Rect aabb = edge_table->aabb;
- Point tl = renddesc.get_tl() - offset;
+ Point tl = renddesc.get_tl() - origin;
Real pw = renddesc.get_pw(),
ph = renddesc.get_ph();
Rect nrect;
- Real pixelfeatherx = abs(feather/pw),
- pixelfeathery = abs(feather/ph);
+ Real pixelfeatherx = quality == 10 ? 0 : abs(feather/pw),
+ pixelfeathery = quality == 10 ? 0 : abs(feather/ph);
nrect.set_point((aabb.minx - tl[0])/pw,(aabb.miny - tl[1])/ph);
nrect.expand((aabb.maxx - tl[0])/pw,(aabb.maxy - tl[1])/ph);
if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
- if(feather)
+ if(feather && quality != 10)
{
//we have to blur rather than be crappy
}
bool
-Layer_Shape::render_shape(Surface *surface,bool useblend,int quality,
+Layer_Shape::render_shape(Surface *surface,bool useblend,int /*quality*/,
const RendDesc &renddesc, ProgressCallback *cb)const
{
int tmp(0);
PolySpan span;
- //optimization for tesselating only inside tiles
+ // if the pixels are zero sized then we're too zoomed out to see anything
+ if (pw == 0 || ph == 0)
+ return true;
+
+ //optimization for tessellating only inside tiles
span.window.minx = 0;
span.window.miny = 0;
span.window.maxx = w;
case Primitive::MOVE_TO:
{
x = data[curnum][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
if(curnum == 0)
{
case Primitive::LINE_TO:
{
x = data[curnum][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
tangent[0] = x - span.cur_x;
tangent[1] = y - span.cur_y;
case Primitive::CONIC_TO:
{
x = data[curnum+1][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum+1][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x1 = data[curnum][0];
- x1 = (x1 - tl[0] + offset[0])*pw;
+ x1 = (x1 - tl[0] + origin[0])*pw;
y1 = data[curnum][1];
- y1 = (y1 - tl[1] + offset[1])*ph;
+ y1 = (y1 - tl[1] + origin[1])*ph;
tangent[0] = 2*(x - x1);
tangent[1] = 2*(y - y1);
case Primitive::CONIC_TO_SMOOTH:
{
x = data[curnum][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x1 = span.cur_x + tangent[0]/2;
y1 = span.cur_y + tangent[1]/2;
case Primitive::CUBIC_TO:
{
x = data[curnum+2][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum+2][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x2 = data[curnum+1][0];
- x2 = (x2 - tl[0] + offset[0])*pw;
+ x2 = (x2 - tl[0] + origin[0])*pw;
y2 = data[curnum+1][1];
- y2 = (y2 - tl[1] + offset[1])*ph;
+ y2 = (y2 - tl[1] + origin[1])*ph;
x1 = data[curnum][0];
- x1 = (x1 - tl[0] + offset[0])*pw;
+ x1 = (x1 - tl[0] + origin[0])*pw;
y1 = data[curnum][1];
- y1 = (y1 - tl[1] + offset[1])*ph;
+ y1 = (y1 - tl[1] + origin[1])*ph;
tangent[0] = 2*(x - x2);
tangent[1] = 2*(y - y2);
case Primitive::CUBIC_TO_SMOOTH:
{
x = data[curnum+1][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum+1][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x2 = data[curnum][0];
- x2 = (x2 - tl[0] + offset[0])*pw;
+ x2 = (x2 - tl[0] + origin[0])*pw;
y2 = data[curnum][1];
- y2 = (y2 - tl[1] + offset[1])*ph;
+ y2 = (y2 - tl[1] + origin[1])*ph;
x1 = span.cur_x + tangent[0]/3.0;
y1 = span.cur_y + tangent[1]/3.0;
}
bool
-Layer_Shape::render_shape(surface<float> *surface,int quality,
- const RendDesc &renddesc, ProgressCallback *cb)const
+Layer_Shape::render_shape(etl::surface<float> *surface,int /*quality*/,
+ const RendDesc &renddesc, ProgressCallback */*cb*/)const
{
// If our amount is set to zero, no need to render anything
if(!get_amount())
PolySpan span;
- //optimization for tesselating only inside tiles
+ //optimization for tessellating only inside tiles
span.window.minx = 0;
span.window.miny = 0;
span.window.maxx = w;
case Primitive::MOVE_TO:
{
x = data[curnum][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
if(curnum == 0)
{
case Primitive::LINE_TO:
{
x = data[curnum][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
tangent[0] = x - span.cur_x;
tangent[1] = y - span.cur_y;
case Primitive::CONIC_TO:
{
x = data[curnum+1][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum+1][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x1 = data[curnum][0];
- x1 = (x1 - tl[0] + offset[0])*pw;
+ x1 = (x1 - tl[0] + origin[0])*pw;
y1 = data[curnum][1];
- y1 = (y1 - tl[1] + offset[1])*ph;
+ y1 = (y1 - tl[1] + origin[1])*ph;
tangent[0] = 2*(x - x1);
tangent[1] = 2*(y - y1);
case Primitive::CONIC_TO_SMOOTH:
{
x = data[curnum][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x1 = span.cur_x + tangent[0]/2;
y1 = span.cur_y + tangent[1]/2;
case Primitive::CUBIC_TO:
{
x = data[curnum+2][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum+2][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x2 = data[curnum+1][0];
- x2 = (x2 - tl[0] + offset[0])*pw;
+ x2 = (x2 - tl[0] + origin[0])*pw;
y2 = data[curnum+1][1];
- y2 = (y2 - tl[1] + offset[1])*ph;
+ y2 = (y2 - tl[1] + origin[1])*ph;
x1 = data[curnum][0];
- x1 = (x1 - tl[0] + offset[0])*pw;
+ x1 = (x1 - tl[0] + origin[0])*pw;
y1 = data[curnum][1];
- y1 = (y1 - tl[1] + offset[1])*ph;
+ y1 = (y1 - tl[1] + origin[1])*ph;
tangent[0] = 2*(x - x2);
tangent[1] = 2*(y - y2);
case Primitive::CUBIC_TO_SMOOTH:
{
x = data[curnum+1][0];
- x = (x - tl[0] + offset[0])*pw;
+ x = (x - tl[0] + origin[0])*pw;
y = data[curnum+1][1];
- y = (y - tl[1] + offset[1])*ph;
+ y = (y - tl[1] + origin[1])*ph;
x2 = data[curnum][0];
- x2 = (x2 - tl[0] + offset[0])*pw;
+ x2 = (x2 - tl[0] + origin[0])*pw;
y2 = data[curnum][1];
- y2 = (y2 - tl[1] + offset[1])*ph;
+ y2 = (y2 - tl[1] + origin[1])*ph;
x1 = span.cur_x + tangent[0]/3.0;
y1 = span.cur_y + tangent[1]/3.0;
if (edge_table->initaabb)
return Rect::zero();
- Rect bounds(edge_table->aabb+offset);
+ Rect bounds(edge_table->aabb+origin);
bounds.expand(max((bounds.get_min() - bounds.get_max()).mag()*0.01,
feather));