bevCircle(0)
{
}
-
+
bool
FilledRect::set_param(const String & param, const ValueBase &value)
{
IMPORT(feather_y);
IMPORT(bevel);
IMPORT(bevCircle);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
FilledRect::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
);
ret.push_back(ParamDesc("point1")
.set_local_name(_("Point 1"))
);
-
+
ret.push_back(ParamDesc("point2")
.set_local_name(_("Point 2"))
);
-
+
ret.push_back(ParamDesc("feather_x")
.set_local_name(_("Feather X"))
);
-
+
ret.push_back(ParamDesc("feather_y")
.set_local_name(_("Feather Y"))
);
-
+
ret.push_back(ParamDesc("bevel")
.set_local_name(_("Bevel"))
);
-
+
ret.push_back(ParamDesc("bevCircle")
.set_local_name(_("Keep Bevel Circular"))
);
-
+
return ret;
}
{
Point p[2] = {point1,point2};
Real swap;
-
+
if(p[0][0] > p[1][0])
{
swap = p[0][0];
p[0][0] = p[1][0];
p[1][0] = swap;
}
-
+
if(p[0][1] > p[1][1])
{
swap = p[0][1];
p[0][1] = p[1][1];
p[1][1] = swap;
}
-
+
/*
p[0][0] -= feather_x;
p[1][0] += feather_x;
if(pos[0] >= p[0][0] && pos[0] <= p[1][0] && pos[1] >= p[0][1] && pos[1] <= p[1][1])
{
Real value = 1;
-
+
if(feather_x > 0)
{
Real xdist = pos[0] - p[0][0];
xdist = min(xdist,p[1][0]-pos[0]);
-
+
if(xdist < feather_x)
{
value = xdist/feather_x;
}
}
-
+
if(feather_y > 0)
{
Real ydist = pos[1]-p[0][1];
ydist = min(ydist,p[1][1]-pos[1]);
-
+
if(ydist < feather_y)
{
value = min(value,(ydist/feather_y));
}
}
-
+
//if we're beveled then check with ellipse code...
if(bevel > 0)
- {
+ {
const Real bev = (bevel > 1) ? 1 : bevel;
const Real bevx = bevCircle ? min(w*bev/2,h*bev/2) : w*bev/2;
const Real bevy = bevCircle ? min(w*bev/2,h*bev/2) : h*bev/2;;
-
+
Vector v(0,0);
bool in = false;
-
+
//based on which quarter it is in (and because it's x/y symmetric) get a positive vector (x/y)
if(pos[0] < p[0][0] + bevx)
{
if(pos[1] < p[0][1] + bevy)
{
v[0] = pos[0] - (p[1][0] - bevx);
- v[1] = p[0][1] + bevy - pos[1];
+ v[1] = p[0][1] + bevy - pos[1];
in = true;
}else if(pos[1] > p[1][1] - bevy)
{
v[0] = pos[0] - (p[1][0] - bevx);
- v[1] = pos[1] - (p[1][1] - bevy);
+ v[1] = pos[1] - (p[1][1] - bevy);
in = true;
- }
+ }
}
-
+
//if it's inside a bevelled block
if(in)
{
const Vector scale(bevx,bevy);
-
+
Vector vc(v[0]/scale[0],v[1]/scale[1]);
Real d = vc.mag();
-
+
//if it's inside the ellipse
if(d < 1)
{
Real val = atan2(vc[1],vc[0]);
val /= (PI/2); //< will always be (0,pi/2) because both components are positive
-
+
Real fthx=1,fthy=1;
-
+
//change d into distance away from edge
d = 1 - d;
-
+
if(feather_x > 0)
- {
+ {
if(scale[0] < feather_x)
{
fthy = scale[0]/feather_x;
}
-
+
if(d*scale[0] < feather_x)
{
fthx = d*scale[0]/feather_x;
}
}
-
+
if(feather_y > 0)
{
if(scale[1] < feather_y)
{
fthx = min(fthx,scale[1]/feather_y);
}
-
+
if(d*scale[1] < feather_y)
{
fthy = min(fthy,d*scale[1]/feather_y);
}
}
-
+
//interpolate
outamount = min(value,((1-val)*fthx + val*fthy)) * get_amount();
out = color;
return true;
-
+
}else return false;
}
}
-
+
outamount = value * get_amount();
out = color;
-
+
return true;
}else
return false;
{
Color clr;
Real amt;
-
+
if(get_color(pos,clr,amt))
{
if(amt==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
bool
FilledRect::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
-{
+{
// Width and Height of a pixel
const Point br(renddesc.get_br()), tl(renddesc.get_tl());
const int w = renddesc.get_w(), h = renddesc.get_h();
-
+
Real wpp = (br[0]-tl[0])/w;
Real hpp = (br[1]-tl[1])/h;
//const Real xneg = wpp<0?-1:1;
- //const Real yneg = hpp<0?-1:1;
-
+ //const Real yneg = hpp<0?-1:1;
+
//the bounds of the rectangle
Point p[2] = {point1,point2};
-
+
if((p[0][0] > p[1][0]) ^ wpp < 0)
{
swap(p[0][0],p[1][0]);
}
-
+
if((p[0][1] > p[1][1]) ^ hpp < 0)
{
swap(p[0][1],p[1][1]);
}
-
+
/*p[0][0] -= xneg*feather_x;
p[1][0] += xneg*feather_x;
p[0][1] -= yneg*feather_y;
p[1][1] += yneg*feather_y;*/
-
+
//the integer coordinates
int y_start = (int)((p[0][1] - tl[1])/hpp +.5); //round start up
int x_start = (int)((p[0][0] - tl[0])/wpp +.5);
int y_end = (int)((p[1][1] - tl[1])/hpp +.5); //and ends up
int x_end = (int)((p[1][0] - tl[0])/wpp +.5);
-
+
y_start = max(0,y_start);
x_start = max(0,x_start);
y_end = min(h,y_end);
x_end = min(w,x_end);
SuperCallback supercb(cb,0,9000,10000);
-
+
if(y_start >= h || x_start > w || x_end < 0 || y_end < 0)
{
if(!context.accelerated_render(surface,quality,renddesc,&supercb))
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
return true;
}
-
+
Real xf_start = tl[0] + x_start*wpp;
Point pos(xf_start,tl[1] + y_start*hpp);
-
+
Color clr = Color::black();
Real amt;
-
+
if(!context.accelerated_render(surface,quality,renddesc,&supercb))
{
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
for(int y = y_start; y < y_end; y++, pos[1] += hpp)
{
pos[0] = xf_start;
for(int x = x_start; x < x_end; x++, pos[0] += wpp)
{
if(get_color(pos,clr,amt))
- {
+ {
if(amt==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
(*surface)[y][x] = clr;
else
(*surface)[y][x] = Color::blend(clr,(*surface)[y][x],amt,get_blend_method());
}
- }
+ }
}
-
+
return true;
-#if 0
+#if 0
//faster version but much more complex
- //the floating point
+ //the floating point
Real y1,y2,y3;
Real x1,x2,x3;
Real dx1,dx2; //reversed in 3rd y section, not used in 2nd
-
- //the transparent
+
+ //the transparent
Real fx = 0, fy = 0;
- Real dfx,dfy;
+ Real dfx,dfy;
//Get the slopes of the lines we need to worry about
if(feather_x)
{
dfx = 1/(fxsize);
-
+
if(fxsize*2 > xfw)
{
x1 = xfw/2;
x1 = fxsize;
x2 = xfw - fxsize;
x3 = xfw;
- }
+ }
}else
{
fx = 1;
x2=xfw;
x3=0;
}
-
+
if(feather_y)
{
dfy = 1/(fysize);
-
+
if(fysize*2 > yfh)
{
y1 = yfh/2;
y2 = yfh - fysize;
y3 = yfh;
}
-
+
dx1 = ph*feather_x/feather_y;
dx2 = -2*dx1;
-
+
}else
{
fy = 1;
}
fy = yf*dfy;
-
+
int x,y;
Real value = 0;
SuperCallback supercb(cb,0,9000,10000);
Surface::pen p;
-
- Real tx1 = 0,tx2 =
+
+ Real tx1 = 0,tx2 =
for(y = y_start;yf < y1; y++,yf++,fy+=dfy, tx1+=dx1)
- {
+ {
fx = xf*dfx;
-
- p = surface->get_pen(x_start,y);
+
+ p = surface->get_pen(x_start,y);
for(; xf < x1; xf++,p.inc_x(), fx+=dfx)
{
//we are in the x portion... use fx
else
p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
}
-
+
for(;xf < x2; xf++,p.inc_x())
{
//we are now in y... use fy
if(value==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
p.put_value(color);
else
- p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
+ p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
}
-
+
fx = xfw?(xfw - xf)/xfw:1;
for(;xf < x3 && ; xf++,p.inc_x(), fx-=dfx)
{
if(value==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
p.put_value(color);
else
- p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
+ p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
}
}
-
- x1 =
+
+ x1 =
for(;fy < 1.0; y++,yf++,fy+=dfy)
{
fx = xf*dfx;
-
- p = surface->get_pen(x_start,y);
+
+ p = surface->get_pen(x_start,y);
for(; xf < x1; xf++,p.inc_x(), fx+=dfx)
{
//we are in the x portion... use fx
else
p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
}
-
+
for(;xf < x2; xf++,p.inc_x())
{
//we are now in y... use fy
if(value==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
p.put_value(color);
else
- p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
+ p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
}
-
+
fx = xfw?(xfw - xf)/xfw:1;
for(;xf < x3 && ; xf++,p.inc_x(), fx-=dfx)
{
if(value==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
p.put_value(color);
else
- p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
+ p.put_value(Color::blend(color,p.get_value(),value,get_blend_method()));
}
}
-
+
for()
{
for(int x = x_start; x < x_end; x++)
{
-
+
}
}
class FilledRect : public synfig::Layer_Composite
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
synfig::Color color;
bool get_color(const synfig::Point &pos, synfig::Color &out, synfig::Real &outamount)const;
public:
-
+
FilledRect();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
-
+
virtual Vocab get_param_vocab()const;
}; // END of class FilledRect
color(Color::black())
{
}
-
+
bool
Metaballs::set_param(const String & param, const ValueBase &value)
{
centers = value;
return true;
}
-
+
if( param=="weights" && value.same_as(weights))
{
weights = value;
return true;
}
-
+
if( param=="radii" && value.same_as(radii))
{
radii = value;
return true;
}
-
+
IMPORT(color);
IMPORT(threshold);
-
+
return Layer_Composite::set_param(param,value);
}
Metaballs::get_param(const String ¶m)const
{
EXPORT(color);
-
+
EXPORT(radii);
- EXPORT(weights);
+ EXPORT(weights);
EXPORT(centers);
EXPORT(threshold);
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
Metaballs::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
);
ret.push_back(ParamDesc("centers")
.set_local_name(_("Points"))
);
-
+
ret.push_back(ParamDesc("radii")
.set_local_name(_("Radii"))
);
-
+
ret.push_back(ParamDesc("weights")
.set_local_name(_("Weights"))
);
-
+
ret.push_back(ParamDesc("threshold")
.set_local_name(_("Threshold"))
);
-
+
return ret;
}
{
const Real dx = p[0] - c[0];
const Real dy = p[1] - c[1];
-
+
const Real n = (1 - (dx*dx + dy*dy)/(R*R));
return (n*n*n);
/*
f(d) = (1 - d^2)^3
f'(d) = -6d * (1 - d^2)^2
-
+
could use this too...
f(d) = (1 - d^2)^2
f'(d) = -6d * (1 - d^2)
Metaballs::totaldensity(const Point &pos) const
{
Real density = 0;
-
+
//sum up weighted functions
for(unsigned int i=0;i<centers.size();i++)
{
density += weights[i] * densityfunc(pos,centers[i], radii[i]);
}
-
+
return density;
}
Metaballs::get_color(Context context, const Point &pos)const
{
Real dens = totaldensity(pos);
-
- if(dens >= threshold)
+
+ if(dens >= threshold)
return color;
else
return context.get_color(pos);
bool
Metaballs::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
-{
+{
// Width and Height of a pixel
- const Point br(renddesc.get_br()),
+ const Point br(renddesc.get_br()),
tl(renddesc.get_tl());
-
- const int w = renddesc.get_w(),
+
+ const int w = renddesc.get_w(),
h = renddesc.get_h();
-
+
Real pw = renddesc.get_pw();
Real ph = renddesc.get_ph();
-
+
SuperCallback supercb(cb,0,9000,10000);
-
+
if(!context.accelerated_render(surface,quality,renddesc,&supercb))
{
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
Point pos(tl[0],tl[1]);
-
+
Real dens;
-
+
if(!context.accelerated_render(surface,quality,renddesc,&supercb))
{
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
for(int y = 0; y < h; y++, pos[1] += ph)
{
pos[0] = tl[0];
for(int x = 0; x < w; x++, pos[0] += pw)
{
dens = totaldensity(pos);
-
+
if(dens >= threshold)
{
(*surface)[y][x] = Color::blend(color,(*surface)[y][x],get_amount(),get_blend_method());
}
- }
+ }
}
// Mark our progress as finished
class Metaballs : public synfig::Layer_Composite
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
synfig::Color color;
synfig::Real threshold;
//Real threshold2;
-
+
synfig::Real totaldensity(const synfig::Point &pos)const;
public:
-
+
Metaballs();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
-
+
virtual Vocab get_param_vocab()const;
}; // END of class Metaballs
radius(0.5)
{
}
-
+
bool
SimpleCircle::set_param(const String & param, const ValueBase &value)
{
IMPORT(color);
IMPORT(center);
IMPORT(radius);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
SimpleCircle::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
);
ret.push_back(ParamDesc("center")
.set_local_name(_("Center"))
);
-
+
ret.push_back(ParamDesc("radius")
.set_local_name(_("Radius"))
.set_description(_("This is the radius of the circle"))
.set_origin("center")
);
-
+
return ret;
}
// Mark our progress as starting
if(cb && !cb->amount_complete(0,1000))
return false;
-
+
surface->set_wh(renddesc.get_w(),renddesc.get_h());
surface->fill(color);
class SimpleCircle : public synfig::Layer_Composite
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
synfig::Color color;
synfig::Real radius;
public:
-
+
SimpleCircle();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
//virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
-
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Vocab get_param_vocab()const;
}; // END of class SimpleCircle
/*Glyph::~Glyph()
{
- if(glyph)FT_Done_Glyph(glyph);
+ if(glyph)FT_Done_Glyph(glyph);
}
*/
void
lyr_freetype::lyr_freetype()
{
face=0;
-
+
size=Vector(0.25,0.25);
text=_("Text Layer");
color=Color::black();
old_version=false;
set_blend_method(Color::BLEND_COMPOSITE);
needs_sync_=true;
-
+
new_font(family,style,weight);
-
+
invert=false;
}
void
lyr_freetype::new_font(const synfig::String &family, int style, int weight)
-{
+{
if(
!new_font_(family,style,weight) &&
!new_font_(family,style,WEIGHT_NORMAL) &&
if(new_face(font_fam_))
return true;
-
+
//start evil hack
for(unsigned int i=0;i<font_fam.size();i++)font_fam[i]=tolower(font_fam[i]);
//end evil hack
else
#endif
font_fam="sans serif";
-
+
if(font_fam=="sans serif" || font_fam=="arial")
{
String arial("arial");
if(new_face(filename))
return true;
}
-
+
if(font_fam=="trebuchet")
{
String filename("trebuc");
if(new_face(filename))
return true;
}
-
-
+
+
if(font_fam=="sans serif" || font_fam=="luxi sans")
{
{
luxi+='r';
if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
luxi+='i';
-
-
+
+
if(new_face(luxi))
return true;
}
luxi+='r';
if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
luxi+='i';
-
+
if(new_face(luxi))
return true;
}
luxi+='r';
if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
luxi+='i';
-
+
if(new_face(luxi))
return true;
}
if(new_face("Times"))
return true;
}
-
+
return new_face(font_fam_) || new_face(font_fam);
-
+
return false;
}
void fss2path(char *path, FSSpec *fss)
{
int l; //fss->name contains name of last item in path
- for(l=0; l<(fss->name[0]); l++) path[l] = fss->name[l + 1];
+ for(l=0; l<(fss->name[0]); l++) path[l] = fss->name[l + 1];
path[l] = 0;
if(fss->parID != fsRtParID) //path is more than just a volume name
- {
+ {
int i, len;
CInfoPBRec pb;
-
+
pb.dirInfo.ioNamePtr = fss->name;
pb.dirInfo.ioVRefNum = fss->vRefNum;
pb.dirInfo.ioDrParID = fss->parID;
do
{
pb.dirInfo.ioFDirIndex = -1; //get parent directory name
- pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+ pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
if(PBGetCatInfoSync(&pb) != noErr) break;
len = fss->name[0] + 1;
char filename[512];
fss2path(filename,&fs_spec);
//FSSpecToNativePathName(fs_spec,filename,sizeof(filename)-1, 0);
-
+
error=FT_New_Face(ft_library, filename, face_index,&face);
//error=FT_New_Face_From_FSSpec(ft_library, &fs_spec, face_index,&face);
synfig::info(__FILE__":%d: \"%s\" (%s) -- ft_error=%d",__LINE__,newfont.c_str(),filename,error);
synfig::info(__FILE__":%d: \"%s\" -- ft_error=%d",__LINE__,newfont.c_str(),error);
// Unable to generate fs_spec
}
-
+
}
#endif
IMPORT_PLUS(vcompress,needs_sync_=true);
IMPORT_PLUS(use_kerning,needs_sync_=true);
IMPORT_PLUS(grid_fit,needs_sync_=true);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(use_kerning);
EXPORT(grid_fit);
EXPORT(invert);
-
+
EXPORT_NAME();
EXPORT_VERSION();
lyr_freetype::sync()
{
needs_sync_=false;
-
-
-
-
+
+
+
+
}
Color
{
if(needs_sync_)
const_cast<lyr_freetype*>(this)->sync();
-
+
if(!face)
return context.get_color(pos);
return context.get_color(pos);
if(needs_sync_)
const_cast<lyr_freetype*>(this)->sync();
-
-
-
+
+
+
int error;
Vector size(lyr_freetype::size*2);
-
+
if(!context.accelerated_render(surface,quality,renddesc,cb))
return false;
-
+
if(is_disabled() || text.empty())
return true;
-
+
// If there is no font loaded, just bail
if(!face)
{
{
text=basename(get_canvas()->get_file_name());
}
-
+
// Width and Height of a pixel
Vector::value_type pw=renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
Vector::value_type ph=renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
//int by=(int)((pos[1]-renddesc.get_tl()[1])*ph*64+0.5);
int bx=0;
int by=0;
-
+
// If the font is the size of a pixel, don't bother rendering any text
if(w<=1 || h<=1)
{
#define CHAR_RESOLUTION (64)
error = FT_Set_Char_Size(
- face, // handle to face object
- (int)CHAR_RESOLUTION, // char_width in 1/64th of points
- (int)CHAR_RESOLUTION, // char_height in 1/64th of points
- round_to_int(abs(size[0]*pw*CHAR_RESOLUTION)), // horizontal device resolution
- round_to_int(abs(size[1]*ph*CHAR_RESOLUTION)) ); // vertical device resolution
+ face, // handle to face object
+ (int)CHAR_RESOLUTION, // char_width in 1/64th of points
+ (int)CHAR_RESOLUTION, // char_height in 1/64th of points
+ round_to_int(abs(size[0]*pw*CHAR_RESOLUTION)), // horizontal device resolution
+ round_to_int(abs(size[1]*ph*CHAR_RESOLUTION)) ); // vertical device resolution
// Here is where we can compensate for the
// error in freetype's rendering engine.
if(grid_fit)
FT_Get_Kerning( face, previous, glyph_index, ft_kerning_default, &delta );
- else
+ else
FT_Get_Kerning( face, previous, glyph_index, ft_kerning_unfitted, &delta );
if(compress<1.0f)
by += delta.y;
}
}
-
+
Glyph curr_glyph;
-
+
// store current pen position
curr_glyph.pos.x = bx;
curr_glyph.pos.y = by;
// record current glyph index
previous = glyph_index;
-
+
// Update the line width
lines.front().width=bx+slot->advance.x;
-
+
// increment pen position
if(multiplier>1)
bx += round_to_int(slot->advance.x*multiplier*compress)-bx%round_to_int(slot->advance.x*multiplier*compress);
by += slot->advance.y*multiplier;
lines.front().glyph_table.push_back(curr_glyph);
-
+
}
-
+
//float string_height;
//string_height=(((lines.size()-1)*face->size->metrics.height+lines.back().actual_height()));
//int string_height=face->size->metrics.ascender;
//#define METRICS_SCALE_ONE (65536.0f)
#define METRICS_SCALE_ONE ((float)(1<<16))
-
+
float line_height;
line_height=vcompress*((float)face->height*(((float)face->size->metrics.y_scale/METRICS_SCALE_ONE)));
string_height=round_to_int(((lines.size()-1)*line_height+lines.back().actual_height()));
//synfig::info("string_height=%d",string_height);
//synfig::info("line_height=%f",line_height);
-
+
/*
-- ** -- RENDER THE GLYPHS ---------------------------------------------------
*/
Surface src_;
Surface *src_surface;
-
+
src_surface=surface;
if(invert)
{
src_=*surface;
Surface::alpha_pen pen(surface->begin(),get_amount(),get_blend_method());
-
+
surface->fill(color,pen,src_.get_w(),src_.get_h());
-
+
src_surface=&src_;
}
-
+
{
std::list<TextLine>::iterator iter;
int curr_line;
by=round_to_int((pos[1]-renddesc.get_tl()[1])*ph*CHAR_RESOLUTION+(1.0-orient[1])*string_height-line_height*curr_line);
//by=round_to_int(vcompress*((pos[1]-renddesc.get_tl()[1])*ph*64+(1.0-orient[1])*string_height-face->size->metrics.height*curr_line));
//synfig::info("curr_line=%d, bx=%d, by=%d",curr_line,bx,by);
-
+
std::vector<Glyph>::iterator iter2;
for(iter2=iter->glyph_table.begin();iter2!=iter->glyph_table.end();++iter2)
{
FT_Glyph image(iter2->glyph);
FT_Vector pen;
FT_BitmapGlyph bit;
-
+
pen.x = bx + iter2->pos.x;
pen.y = by + iter2->pos.y;
-
+
//synfig::info("GLYPH: pen.x=%d, pen,y=%d",curr_line,(pen.x+32)>>6,(pen.y+32)>>6);
-
+
error = FT_Glyph_To_Bitmap( &image, ft_render_mode_normal,0/*&pen*/, 1 );
if(error) { FT_Done_Glyph( image ); continue; }
-
+
bit = (FT_BitmapGlyph)image;
for(v=0;v<bit->bitmap.rows;v++)
(*surface)[y][x]=Color::blend(color,(*src_surface)[y][x],myamount*get_amount(),get_blend_method());
}
}
-
+
FT_Done_Glyph( image );
}
//iter->clear_and_free();
}
}
-
+
return true;
}
TextLine():width(0) { }
void clear_and_free();
-
+
int actual_height()const
{
int height(0);
-
+
std::vector<Glyph>::const_iterator iter;
for(iter=glyph_table.begin();iter!=glyph_table.end();++iter)
{
FT_BBox glyph_bbox;
-
+
//FT_Glyph_Get_CBox( glyphs[n], ft_glyph_bbox_pixels, &glyph_bbox );
FT_Glyph_Get_CBox( iter->glyph, ft_glyph_bbox_subpixels, &glyph_bbox );
-
+
if(glyph_bbox.yMax>height)
height=glyph_bbox.yMax;
}
return height;
- }
+ }
};
bool needs_sync_;
void sync();
-
+
mutable synfig::Mutex mutex;
-
+
public:
lyr_freetype();
virtual ~lyr_freetype();
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const synfig::Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
-
+
virtual Vocab get_param_vocab()const;
virtual bool set_version(const String &ver){if(ver=="0.1")old_version=true;return true;}
IMPORT(type);
IMPORT(use_luma);
IMPORT(solid);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(angle);
EXPORT(use_luma);
EXPORT(solid);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Color
if(get_amount()==0.0)
return context.get_color(pos);
-
+
Color shade;
Real hi_alpha(1.0f-context.get_color(blurpos+offset).get_a());
Real lo_alpha(1.0f-context.get_color(blurpos-offset).get_a());
-
+
Real shade_alpha(hi_alpha-lo_alpha);
if(shade_alpha>0)
shade=color1,shade.set_a(shade_alpha);
- else
+ else
shade=color2,shade.set_a(-shade_alpha);
-
+
return Color::blend(shade,context.get_color(pos),get_amount(),get_blend_method());
}
int x,y;
SuperCallback stageone(cb,0,5000,10000);
SuperCallback stagetwo(cb,5000,10000,10000);
-
+
const int w = renddesc.get_w(),
h = renddesc.get_h();
const Real pw = renddesc.get_pw(),
ph = renddesc.get_ph();
const Vector size(softness,softness);
-
+
RendDesc workdesc(renddesc);
Surface worksurface;
etl::surface<float> blurred;
-
+
//callbacks depend on how long the blur takes
if(size[0] || size[1])
{
if(type == Blur::DISC)
{
stageone = SuperCallback(cb,0,5000,10000);
- stagetwo = SuperCallback(cb,5000,10000,10000);
+ stagetwo = SuperCallback(cb,5000,10000,10000);
}
else
{
stageone = SuperCallback(cb,0,9000,10000);
- stagetwo = SuperCallback(cb,9000,10000,10000);
+ stagetwo = SuperCallback(cb,9000,10000,10000);
}
}
else
{
stageone = SuperCallback(cb,0,9999,10000);
- stagetwo = SuperCallback(cb,9999,10000,10000);
+ stagetwo = SuperCallback(cb,9999,10000,10000);
}
-
+
//expand the working surface to accommodate the blur
-
+
//the expanded size = 1/2 the size in each direction rounded up
int halfsizex = (int) (abs(size[0]*.5/pw) + 3),
halfsizey = (int) (abs(size[1]*.5/ph) + 3);
w+abs(offset_u),
h+abs(offset_v)
);
-
+
//expand by 1/2 size in each direction on either side
switch(type)
{
#define GAUSSIAN_ADJUSTMENT (0.05)
Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
-
+
pw=pw*pw;
ph=ph*ph;
halfsizex = (halfsizex + 1)/2;
halfsizey = (halfsizey + 1)/2;
workdesc.set_subwindow( -halfsizex, -halfsizey, offset_w+2*halfsizex, offset_h+2*halfsizey );
-
+
break;
}
}
-
+
//render the background onto the expanded surface
if(!context.accelerated_render(&worksurface,quality,workdesc,&stageone))
return false;
//be sure the surface is of the correct size
surface->set_wh(renddesc.get_w(),renddesc.get_h());
-
+
int u = halfsizex+abs(offset_u), v = halfsizey+abs(offset_v);
for(y=0;y<renddesc.get_h();y++,v++)
{
alpha/=2;
if(alpha>0)
shade=color1,shade.set_a(shade.get_a()*alpha);
- else
+ else
shade=color2,shade.set_a(shade.get_a()*-alpha);
}
-
-
+
+
if(shade.get_a())
{
(*surface)[y][x]=Color::blend(shade,worksurface[v][u],get_amount(),get_blend_method());
else (*surface)[y][x] = worksurface[v][u];
}
}
-
+
if(cb && !cb->amount_complete(10000,10000))
{
//if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
return true;
}
-
+
Layer::Vocab
Layer_Bevel::get_param_vocab(void)const
{
ret.push_back(ParamDesc("solid")
.set_local_name(_("Solid"))
);
-
+
return ret;
}
Rect bounds(under.expand(softness));
bounds.expand_x(abs(depth));
bounds.expand_y(abs(depth));
-
+
return bounds;
}
synfig::Color color1;
synfig::Color color2;
-
+
synfig::Angle angle;
synfig::Real depth;
synfig::Vector offset;
synfig::Vector offset45;
-
+
bool use_luma;
bool solid;
void calc_offset();
public:
Layer_Bevel();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
}
bool BooleanCurve::set_param(const String & param, const synfig::ValueBase &value)
-{
- if(param=="regions" && value.same_as(regions))
+{
+ if(param=="regions" && value.same_as(regions))
{
vector<BLinePoint> bv;
int size = value.get_list().size();
-
+
const vector<ValueBase> &vlist = value.get_list();
-
- regions.clear();
+
+ regions.clear();
for(int i = 0; i < size; ++i)
{
regions.push_back(vector<BLinePoint>(vlist[i].get_list().begin(),vlist[i].get_list().end()));
}
return true;
}
-
+
return Layer_Shape::set_param(param,value);
}
ValueBase BooleanCurve::get_param(const String & param)const
{
EXPORT(regions);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
+
return Layer_Shape::get_param(param);
}
Layer::Vocab BooleanCurve::get_param_vocab()const
{
Layer::Vocab ret(Layer_Shape::get_param_vocab());
-
+
ret.push_back(ParamDesc("regions")
.set_local_name(_("Region Set"))
.set_description(_("Set of regions to combine"))
);
-
+
return ret;
}
Color BooleanCurve::get_color(Context context, const Point &pos)const
{
Color c(Color::alpha());
-
+
return c;
}
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig
{
-
+
class BooleanCurve : public Layer_Shape
{
//dynamic list of regions and such
typedef std::vector< std::vector<BLinePoint> > region_list_type;
region_list_type regions;
-
+
enum BOOLEAN_OP
{
Union = 0,
MutualExclude,
Num_Boolean_Ops
};
-
+
int operation;
-
+
public:
BooleanCurve();
~BooleanCurve();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
-
+
virtual Vocab get_param_vocab()const;
virtual Color get_color(Context context, const Point &pos)const;
- virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
+ virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
};
} //end of namespace synfig
Layer_Clamp::clamp_color(const Color &in)const
{
Color ret(in);
-
+
if(ret.get_a()==0)
return Color::alpha();
{
if(ret.get_a()<floor)
ret=-ret;
-
+
if(ret.get_r()<floor)
{
ret.set_g(ret.get_g()-ret.get_r());
}
return ret;
}
-
+
bool
Layer_Clamp::set_param(const String & param, const ValueBase &value)
{
IMPORT(clamp_ceiling);
IMPORT(ceiling);
IMPORT(floor);
-
- return false;
+
+ return false;
}
ValueBase
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Layer_Clamp::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("invert_negative")
.set_local_name(_("Invert Negative"))
);
ret.push_back(ParamDesc("floor")
.set_local_name(_("Floor"))
);
-
+
return ret;
}
{
return clamp_color(context.get_color(pos));
}
-
+
bool
Layer_Clamp::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
class Layer_Clamp : public Layer
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
bool invert_negative;
Color clamp_color(const Color &in)const;
public:
-
+
Layer_Clamp();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual Rect get_full_bounding_rect(Context context)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
-
+
virtual Vocab get_param_vocab()const;
}; // END of class Layer_Clamp
surface.clear();
return true;
}
-
+
String newfilename=value.get(string());
String filename_with_path;
-
+
// Get rid of any %20 crap
{
unsigned int n;
while((n=newfilename.find("%20"))!=String::npos)
newfilename.replace(n,3," ");
}
-
+
//if(get_canvas()->get_file_path()==dirname(newfilename))
//{
// synfig::info("Image seems to be in local directory. Adjusting path...");
// newfilename=basename(newfilename);
//}
-
+
#ifndef WIN32
if(is_absolute_path(newfilename))
{
string curpath(cleanup_path(absolute_path(get_canvas()->get_file_path())));
while(basename(curpath)==".")curpath=dirname(curpath);
-
+
newfilename=relative_path(curpath,newfilename);
synfig::info("basename(curpath)=%s, Path adjusted to %s",basename(curpath).c_str(),newfilename.c_str());
}
surface.clear();
return true;
}
-
+
// If we are already loaded, don't reload
if(filename==newfilename && importer)
{
synfig::warning(strprintf(_("Filename seems to already be set to \"%s\" (%s)"),filename.c_str(),newfilename.c_str()));
return true;
}
-
+
assert(get_canvas());
-
+
if(is_absolute_path(newfilename))
filename_with_path=newfilename;
else
filename_with_path=get_canvas()->get_file_path()+ETL_DIRECTORY_SEPERATOR+newfilename;
-
+
handle<Importer> newimporter;
-
+
newimporter=Importer::open(absolute_path(filename_with_path));
if(!newimporter)
importer=newimporter;
filename=newfilename;
abs_filename=absolute_path(filename_with_path);
-
+
return true;
}
} catch(...) { set_amount(0); return false; }
-
+
return Layer_Bitmap::set_param(param,value);
}
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Bitmap::get_param(param);
+
+ return Layer_Bitmap::get_param(param);
}
Layer::Vocab
Import::get_param_vocab()const
{
Layer::Vocab ret(Layer_Bitmap::get_param_vocab());
-
+
ret.push_back(ParamDesc("filename")
.set_local_name(_("Filename"))
.set_description(_("File to import"))
ret.push_back(ParamDesc("time_offset")
.set_local_name(_("Time Offset"))
);
-
+
return ret;
}
public:
~Import();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
- virtual synfig::ValueBase get_param(const synfig::String & param)const;
+ virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual Vocab get_param_vocab()const;
origin(0,0)
{
}
-
+
bool
InsideOut::set_param(const String & param, const ValueBase &value)
{
InsideOut::get_param(const String & param)const
{
EXPORT(origin);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
synfig::Layer::Handle
etl::handle<const InsideOut> layer;
public:
InsideOut_Trans(const InsideOut* x):layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
Point pos(x-layer->origin);
return (pos*(inv_mag*inv_mag)+layer->origin);
return x;
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
Point pos(x-layer->origin);
InsideOut::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("origin")
.set_local_name(_("Origin"))
.set_description(_("Defines the where the center will be"))
);
-
+
return ret;
}
public:
InsideOut();
-
+
virtual bool set_param(const String ¶m, const ValueBase &value);
virtual ValueBase get_param(const String ¶m)const;
virtual Color get_color(Context context, const Point &pos)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
- virtual Vocab get_param_vocab()const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ virtual Vocab get_param_vocab()const;
virtual etl::handle<synfig::Transform> get_transform()const;
};
bailout=4;
lp=log(log(bailout));
}
-
+
bool
Julia::set_param(const String & param, const ValueBase &value)
{
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Color
cr, ci,
zr, zi,
zr_hold;
-
+
ColorReal
depth, mag;
-
+
Color
ret;
-
+
cr=seed[0];
ci=seed[1];
zr=pos[0];
zi=pos[1];
-
+
for(int i=0;i<iterations;i++)
{
// Perform complex multiplication
// Use "broken" algorithm, if requested (looks weird)
if(broken)zr+=zi;
-
+
// Calculate Magnitude
mag=zr*zr+zi*zi;
if(mag>4)
- {
+ {
if(smooth_outside)
{
// Darco's original mandelbrot smoothing algo
if(color_cycle)
ret=ret.rotate_uv(color_shift.operator*(depth)).clamped_negative();
-
+
if(shade_outside)
{
ColorReal alpha=depth/static_cast<ColorReal>(iterations);
return ret;
}
-
+
Layer::Vocab
Julia::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("icolor")
.set_local_name(_("Inside Color"))
.set_description(_("Color of the Set"))
ret.push_back(ParamDesc("bailout")
.set_local_name(_("Bailout ValueBase"))
);
-
+
ret.push_back(ParamDesc("distort_inside")
.set_local_name(_("Distort Inside"))
);
ret.push_back(ParamDesc("color_outside")
.set_local_name(_("Color Outside"))
);
-
+
ret.push_back(ParamDesc("color_cycle")
.set_local_name(_("Color Cycle"))
);
.set_local_name(_("Break Set"))
.set_description(_("Modify equation to achieve interesting results"))
);
-
-
+
+
return ret;
}
bool shade_inside;
bool shade_outside;
bool solid_inside;
- bool solid_outside;
+ bool solid_outside;
bool invert_inside;
bool invert_outside;
bool color_inside;
public:
Julia();
-
+
virtual bool set_param(const synfig::String ¶m, const synfig::ValueBase &value);
virtual ValueBase get_param(const synfig::String ¶m)const;
virtual Color get_color(synfig::Context context, const synfig::Point &pos)const;
- virtual Vocab get_param_vocab()const;
+ virtual Vocab get_param_vocab()const;
};
/* === E N D =============================================================== */
smooth_outside=true;
broken=false;
-
+
bailout=4;
lp=log(log(bailout));
}
-
+
bool
Mandelbrot::set_param(const String & param, const ValueBase &value)
{
IMPORT(gradient_offset_outside);
IMPORT(gradient_loop_inside);
IMPORT(gradient_scale_outside);
-
+
IMPORT(distort_inside);
IMPORT(distort_outside);
IMPORT(solid_inside);
IMPORT(gradient_inside);
IMPORT(gradient_outside);
-
+
if(param=="iterations" && value.same_as(iterations))
{
iterations=value.get(iterations);
EXPORT(gradient_inside);
EXPORT(gradient_outside);
-
+
if(param=="bailout")
return sqrt(bailout);
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Mandelbrot::get_param_vocab()const
{
Layer::Vocab ret;
-
-
+
+
ret.push_back(ParamDesc("iterations")
.set_local_name(_("Iterations"))
);
.set_description(_("Modify equation to achieve interesting results"))
);
-
+
ret.push_back(ParamDesc("distort_inside")
.set_local_name(_("Distort Inside"))
.set_group(_("Inside"))
.set_local_name(_("Scale Outside"))
.set_group(_("Outside"))
);
-
+
return ret;
}
cr, ci,
zr, zi,
zr_hold;
-
+
ColorReal
depth, mag;
-
+
Color
ret;
-
+
zr=zi=0;
cr=pos[0];
ci=pos[1];
-
+
for(int i=0;i<iterations;i++)
{
// Perform complex multiplication
if(broken)zr+=zi; // Use "broken" algorithm, if requested (looks weird)
zi=zr_hold*zi*2 + ci;
-
+
// Calculate Magnitude
mag=zr*zr+zi*zi;
if(mag>bailout)
- {
+ {
if(smooth_outside)
{
// Darco's original mandelbrot smoothing algo
ColorReal amount(depth/static_cast<ColorReal>(iterations));
amount=amount*gradient_scale_outside+gradient_offset_outside;
amount-=floor(amount);
-
+
if(solid_outside)
ret=gradient_outside(amount);
else
ret=context.get_color(Point(pos[0]+zr,pos[1]+zi));
else
ret=context.get_color(pos);
-
+
if(invert_outside)
ret=~ret;
ret=Color::blend(gradient_outside(amount), ret, 1.0);
}
-
+
return ret;
}
}
ret=context.get_color(Point(pos[0]+zr,pos[1]+zi));
else
ret=context.get_color(pos);
-
+
if(invert_inside)
ret=~ret;
if(shade_inside)
ret=Color::blend(gradient_inside(amount), ret, 1.0);
}
-
+
return ret;
}
bool distort_inside;
bool distort_outside;
bool solid_inside;
- bool solid_outside;
+ bool solid_outside;
bool invert_inside;
bool invert_outside;
bool shade_outside;
public:
Mandelbrot();
-
+
virtual bool set_param(const String ¶m, const ValueBase &value);
virtual ValueBase get_param(const String ¶m)const;
virtual Color get_color(Context context, const Point &pos)const;
- virtual Vocab get_param_vocab()const;
+ virtual Vocab get_param_vocab()const;
};
/* === E N D =============================================================== */
zigzag(false)
{
}
-
+
bool
RadialGradient::set_param(const String & param, const ValueBase &value)
{
IMPORT(radius);
IMPORT(loop);
IMPORT(zigzag);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(radius);
EXPORT(loop);
EXPORT(zigzag);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
RadialGradient::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("gradient")
.set_local_name(_("Gradient"))
);
ret.push_back(ParamDesc("center")
.set_local_name(_("Center"))
);
-
+
ret.push_back(ParamDesc("radius")
.set_local_name(_("Radius"))
.set_description(_("This is the radius of the circle"))
ret.push_back(ParamDesc("zigzag")
.set_local_name(_("Zig-Zag"))
);
-
+
return ret;
}
RadialGradient::color_func(const Point &point, float supersample)const
{
Real dist((point-center).mag()/radius);
-
+
if(zigzag)
{
dist*=2.0;
}
}
}
-
+
return gradient(dist,supersample);
}
else
return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method());
}
-
+
bool
RadialGradient::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
Rotate::set_param(const String & param, const ValueBase &value)
{
IMPORT(origin);
-
+
if(param=="amount" && value.same_as(amount))
{
amount=value.get(amount);
cos_val=Angle::cos(amount).get();
return true;
}
-
+
return false;
}
{
EXPORT(origin);
EXPORT(amount);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Rotate::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("origin")
.set_local_name(_("Origin"))
.set_description(_("Point where you want the origin to be"))
.set_description(_("Amount of rotation"))
.set_origin("origin")
);
-
+
return ret;
}
etl::handle<const Rotate> layer;
public:
Rotate_Trans(const Rotate* x):Transform(x->get_guid()),layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
Point pos(x-layer->origin);
return Point(layer->cos_val*pos[0]-layer->sin_val*pos[1],layer->sin_val*pos[0]+layer->cos_val*pos[1])+layer->origin;
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
Point pos(x-layer->origin);
SuperCallback stageone(cb,0,9000,10000);
SuperCallback stagetwo(cb,9000,10000,10000);
-
+
if(cb && !cb->amount_complete(0,10000))
return false;
-
+
Point tl(renddesc.get_tl()-origin);
Point br(renddesc.get_br()-origin);
Point rot_tl(cos_val*tl[0]+sin_val*tl[1],-sin_val*tl[0]+cos_val*tl[1]);
- Point rot_br(cos_val*br[0]+sin_val*br[1],-sin_val*br[0]+cos_val*br[1]);
+ Point rot_br(cos_val*br[0]+sin_val*br[1],-sin_val*br[0]+cos_val*br[1]);
Point rot_tr(cos_val*br[0]+sin_val*tl[1],-sin_val*br[0]+cos_val*tl[1]);
- Point rot_bl(cos_val*tl[0]+sin_val*br[1],-sin_val*tl[0]+cos_val*br[1]);
+ Point rot_bl(cos_val*tl[0]+sin_val*br[1],-sin_val*tl[0]+cos_val*br[1]);
rot_tl+=origin;
rot_br+=origin;
rot_tr+=origin;
rot_bl+=origin;
-
+
Point min_point(min(min(min(rot_tl[0],rot_br[0]),rot_tr[0]),rot_bl[0]),min(min(min(rot_tl[1],rot_br[1]),rot_tr[1]),rot_bl[1]));
Point max_point(max(max(max(rot_tl[0],rot_br[0]),rot_tr[0]),rot_bl[0]),max(max(max(rot_tl[1],rot_br[1]),rot_tr[1]),rot_bl[1]));
br[1]=max_point[1];
tl[1]=min_point[1];
}
-
+
Real pw=(renddesc.get_w())/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
Real ph=(renddesc.get_h())/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
-
+
RendDesc desc(renddesc);
desc.clear_flags();
//desc.set_flags(RendDesc::PX_ASPECT);
//synfig::warning("given window: [%f,%f]-[%f,%f] %dx%d",renddesc.get_tl()[0],renddesc.get_tl()[1],renddesc.get_br()[0],renddesc.get_br()[1],renddesc.get_w(),renddesc.get_h());
//synfig::warning("surface to render: [%f,%f]-[%f,%f] %dx%d",desc.get_tl()[0],desc.get_tl()[1],desc.get_br()[0],desc.get_br()[1],desc.get_w(),desc.get_h());
-
+
Surface source;
source.set_wh(desc.get_w(),desc.get_h());
if(!context.accelerated_render(&source,quality,desc,&stageone))
return false;
-
+
surface->set_wh(renddesc.get_w(),renddesc.get_h());
Surface::pen pen(surface->begin());
private:
Vector origin;
Angle amount;
-
+
Real sin_val;
Real cos_val;
public:
Rotate();
~Rotate();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const synfig::String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
- virtual Vocab get_param_vocab()const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ virtual Vocab get_param_vocab()const;
virtual Rect get_full_bounding_rect(Context context)const;
virtual etl::handle<synfig::Transform> get_transform()const;
IMPORT(color);
IMPORT(offset);
IMPORT(invert);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(color);
EXPORT(offset);
EXPORT(invert);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Color
if(get_amount()==0.0)
return context.get_color(pos);
-
+
Color shade(color);
if(!invert)
Layer_Shade::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
int x,y;
-
+
const int w = renddesc.get_w(),
h = renddesc.get_h();
const Real pw = renddesc.get_pw(),
ph = renddesc.get_ph();
-
+
RendDesc workdesc(renddesc);
Surface worksurface;
etl::surface<float> blurred;
-
+
//expand the working surface to accommodate the blur
-
+
//the expanded size = 1/2 the size in each direction rounded up
int halfsizex = (int) (abs(size[0]*.5/pw) + 3),
halfsizey = (int) (abs(size[1]*.5/ph) + 3);
halfsizex/=4;
halfsizey/=4;
}
-
+
//expand by 1/2 size in each direction on either side
switch(type)
{
#define GAUSSIAN_ADJUSTMENT (0.05)
Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
-
+
pw=pw*pw;
ph=ph*ph;
halfsizex = (halfsizex + 1)/2;
halfsizey = (halfsizey + 1)/2;
workdesc.set_subwindow( -halfsizex, -halfsizey, offset_w+2*halfsizex, offset_h+2*halfsizey );
-
+
break;
}
}
{
SuperCallback stageone(cb,0,5000,10000);
SuperCallback stagetwo(cb,5000,10000,10000);
-
+
//callbacks depend on how long the blur takes
if(size[0] || size[1])
{
if(type == Blur::DISC)
{
stageone = SuperCallback(cb,0,5000,10000);
- stagetwo = SuperCallback(cb,5000,10000,10000);
+ stagetwo = SuperCallback(cb,5000,10000,10000);
}
else
{
stageone = SuperCallback(cb,0,9000,10000);
- stagetwo = SuperCallback(cb,9000,10000,10000);
+ stagetwo = SuperCallback(cb,9000,10000,10000);
}
}
else
{
stageone = SuperCallback(cb,0,9999,10000);
- stagetwo = SuperCallback(cb,9999,10000,10000);
+ stagetwo = SuperCallback(cb,9999,10000,10000);
}
//render the background onto the expanded surface
if(!context.accelerated_render(&worksurface,quality,workdesc,&stageone))
return false;
-
+
// Copy over the alpha
blurred.set_wh(worksurface.get_w(),worksurface.get_h());
for(int j=0;j<worksurface.get_h();j++)
{
blurred[j][i]=worksurface[j][i].get_a();
}
-
+
//blur the image
Blur(size,type,&stagetwo)(blurred,workdesc.get_br()-workdesc.get_tl(),blurred);
-
+
//be sure the surface is of the correct size
surface->set_wh(renddesc.get_w(),renddesc.get_h());
-
+
int u = halfsizex-(offset_u<0?offset_u:0), v = halfsizey-(offset_v<0?offset_v:0);
for(y=0;y<renddesc.get_h();y++,v++)
{
for(x=0;x<renddesc.get_w();x++,u++)
{
Color a(color);
-
+
if(!invert)
a.set_a(blurred.linear_sample(offset_u+(float)u,offset_v+(float)v));
else
a.set_a(1.0f-blurred.linear_sample(offset_u+(float)u,offset_v+(float)v));
-
+
if(a.get_a() || get_blend_method()==Color::BLEND_STRAIGHT)
{
(*surface)[y][x]=Color::blend(a,worksurface[v][u],get_amount(),get_blend_method());
}
else
{
-
+
SuperCallback stageone(cb,0,5000,10000);
SuperCallback stagetwo(cb,5000,10000,10000);
-
+
//callbacks depend on how long the blur takes
if(size[0] || size[1])
{
if(type == Blur::DISC)
{
stageone = SuperCallback(cb,0,5000,10000);
- stagetwo = SuperCallback(cb,5000,10000,10000);
+ stagetwo = SuperCallback(cb,5000,10000,10000);
}
else
{
stageone = SuperCallback(cb,0,9000,10000);
- stagetwo = SuperCallback(cb,9000,10000,10000);
+ stagetwo = SuperCallback(cb,9000,10000,10000);
}
}
else
{
stageone = SuperCallback(cb,0,9999,10000);
- stagetwo = SuperCallback(cb,9999,10000,10000);
+ stagetwo = SuperCallback(cb,9999,10000,10000);
}
int fw(floor_to_int(abs(size[0]/(pw*SCALE_FACTOR)))+1);
int fh(floor_to_int(abs(size[1]/(ph*SCALE_FACTOR)))+1);
int tmpw(round_to_int((float)workdesc.get_w()/fw)),tmph(round_to_int((float)workdesc.get_h()/fh));
-
+
workdesc.clear_flags();
workdesc.set_wh(tmpw,tmph);
//synfig::info("fw: %d, fh: %d",fw,fh);
for(int j=0;j<worksurface.get_h();j++)
for(int i=0;i<worksurface.get_w();i++)
blurred[j][i]=worksurface[j][i].get_a();
-
+
//blur the image
Blur(size,type,&stagetwo)(blurred,workdesc.get_br()-workdesc.get_tl(),blurred);
for(x=0;x<renddesc.get_w();x++,u++)
{
Color a(color);
-
+
if(!invert)
a.set_a(blurred.linear_sample(((float)offset_u+(float)u)/(float)fw,((float)offset_v+(float)v)/(float)fh));
else
a.set_a(1.0f-blurred.linear_sample(((float)offset_u+(float)u)/fw,((float)offset_v+(float)v)/(float)fh));
-
+
if(a.get_a() || get_blend_method()==Color::BLEND_STRAIGHT)
{
(*surface)[y][x]=Color::blend(a,(*surface)[y][x],get_amount(),get_blend_method());
}
}
}
-
-
+
+
if(cb && !cb->amount_complete(10000,10000))
{
//if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
return true;
}
-
+
Layer::Vocab
Layer_Shade::get_param_vocab(void)const
{
.add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
.add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
);
-
+
ret.push_back(ParamDesc("invert")
.set_local_name(_("Invert"))
);
-
+
return ret;
}
if(is_solid_color())
return bounds;
-
+
return bounds|under;
}
public:
Layer_Shade();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
{
}
-
+
bool
Layer_SphereDistort::set_param(const String & param, const ValueBase &value)
{
else
synfig::warning("Layer_SphereDistort::::set_param(): The parameter \"segment_list\" is deprecated. Use \"bline\" instead.");
}
-
- return false;
+
+ return false;
}
ValueBase
EXPORT(type);
EXPORT_AS(percent,"amount");
EXPORT(clip);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
+
return ValueBase();
}
Layer_SphereDistort::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("center")
.set_local_name(_("Position"))
);
-
+
ret.push_back(ParamDesc("radius")
.set_local_name(_("Radius"))
.set_origin("center")
.set_is_distance()
);
-
+
ret.push_back(ParamDesc("amount")
.set_local_name(_("Amount"))
.set_is_distance(false)
ret.push_back(ParamDesc("clip")
.set_local_name(_("Clip"))
);
-
+
ret.push_back(ParamDesc("type")
.set_local_name(_("Distort Type"))
.set_description(_("The direction of the distortion"))
.add_enum_value(TYPE_DISTH,"honly",_("Vertical Bar"))
.add_enum_value(TYPE_DISTV,"vonly",_("Horizontal Bar"))
);
-
+
return ret;
}
/*
Spherical Distortion: maps an image onto a ellipsoid of some sort
-
- so the image coordinate (i.e. distance away from the center)
+
+ so the image coordinate (i.e. distance away from the center)
will determine how things get mapped
-
+
so with the radius and position the mapping would go as follows
-
+
r = (pos - center) / radius clamped to [-1,1]
-
+
if it's outside of that range then it's not distorted
but if it's inside of that range then it goes as follows
-
+
angle = r * pi/2 (-pi/2,pi/2)
-
+
newr = cos(angle)*radius
-
+
the inverse of this is (which is actually what we'd be transforming it from
-
+
*/
inline float spherify(float f)
else return f;
}
-Point sphtrans(const Point &p, const Point ¢er, const float &radius,
+Point sphtrans(const Point &p, const Point ¢er, const float &radius,
const Real &percent, int type, bool& clipped)
{
const Vector v = (p - center) / radius;
-
+
Point newp = p;
const float t = percent;
-
+
clipped=false;
-
+
if(type == TYPE_NORMAL)
{
const float m = v.mag();
float lerp(0);
-
+
if(m <= -1 || m >= 1)
{
clipped=true;
{
lerp = (t*unspherify(m) + (1-t)*m);
}else if(t < 0)
- {
+ {
lerp = ((1+t)*m - t*spherify(m));
}else lerp = m;
-
+
const float d = lerp*radius;
newp = center + v*(d/m);
}
-
+
else if(type == TYPE_DISTH)
{
float lerp(0);
{
lerp = ((1+t)*v[0] - t*spherify(v[0]));
}else lerp = v[0];
-
+
newp[0] = center[0] + lerp*radius;
}
-
+
else if(type == TYPE_DISTV)
{
float lerp(0);
{
lerp = ((1+t)*v[1] - t*spherify(v[1]));
}else lerp = v[1];
-
+
newp[1] = center[1] + lerp*radius;
}
-
+
return newp;
}
-inline Point sphtrans(const Point &p, const Point ¢er, const Real &radius,
+inline Point sphtrans(const Point &p, const Point ¢er, const Real &radius,
const Real &percent, int type)
{
bool tmp;
2) Bounding box clipping
3) Super sampling for better visual quality (based on the quality level?)
4) Interpolation type for sampling (based on quality level?)
-
+
//things to defer until after
super sampling, non-linear interpolation
*/
-
+
//bounding box reject
{
Rect sphr;
-
+
sphr.set_point(center[0]-radius,center[1]-radius);
sphr.expand(center[0]+radius,center[1]+radius);
- //get the bounding box of the transform
+ //get the bounding box of the transform
Rect windr;
-
- //and the bounding box of the rendering
+
+ //and the bounding box of the rendering
windr.set_point(renddesc.get_tl()[0],renddesc.get_tl()[1]);
windr.expand(renddesc.get_br()[0],renddesc.get_br()[1]);
-
+
//test bounding boxes for collision
if( (type == TYPE_NORMAL && !intersect(sphr,windr)) ||
(type == TYPE_DISTH && (sphr.minx >= windr.maxx || windr.minx >= sphr.maxx)) ||
//synfig::warning("Spherize: Bounding box reject");
return context.accelerated_render(surface,quality,renddesc,cb);
}
-
+
//synfig::warning("Spherize: Bounding box accept");
}
-
+
//Ok, so we overlap some... now expand the window for rendering
RendDesc r = renddesc;
Surface background;
Real pw = renddesc.get_pw(),ph = renddesc.get_ph();
-
+
int nl=0,nt=0,nr=0,nb=0, nw=0,nh=0;
Point tl = renddesc.get_tl(), br = renddesc.get_br();
-
- {
+
+ {
//must enlarge window by pixel coordinates so go!
-
+
//need to figure out closest and farthest point and distort THOSE
-
+
Point origin[4] = {tl,tl,br,br};
Vector v[4] = {Vector(0,br[1]-tl[1]),
Vector(br[0]-tl[0],0),
Vector(0,tl[1]-br[1]),
Vector(tl[0]-br[0],0)};
-
+
Point close(0,0);
Real t = 0;
Rect expandr(tl,br);
-
+
//expandr.set_point(tl[0],tl[1]);
//expandr.expand(br[0],br[1]);
- //synfig::warning("Spherize: Loop through lines and stuff");
+ //synfig::warning("Spherize: Loop through lines and stuff");
for(int i=0; i<4; ++i)
{
//synfig::warning("Spherize: %d", i);
Vector p_o = center-origin[i];
-
+
//project onto left line
t = (p_o*v[i])/v[i].mag_squared();
-
+
//clamp
if(t < 0) t = 0; if(t > 1) t = 1;
-
+
close = origin[i] + v[i]*t;
-
+
//now get transforms and expand the rectangle to accomodate
Point p = sphtrans(close,center,radius,percent,type);
expandr.expand(p[0],p[1]);
p = sphtrans(origin[i]+v[i],center,radius,percent,type);
expandr.expand(p[0],p[1]);
}
-
+
/*synfig::warning("Spherize: Bounding box (%f,%f)-(%f,%f)",
expandr.minx,expandr.miny,expandr.maxx,expandr.maxy);*/
-
+
//now that we have the bouding rectangle of ALL the pixels (should be...)
//order it so that it's in the same orientation as the tl,br pair
//synfig::warning("Spherize: Organize like tl,br");
Point ntl(0,0),nbr(0,0);
-
+
//sort x
if(tl[0] < br[0])
- {
+ {
ntl[0] = expandr.minx;
nbr[0] = expandr.maxx;
}
else
{
ntl[0] = expandr.maxx;
- nbr[0] = expandr.minx;
+ nbr[0] = expandr.minx;
}
-
+
//sort y
if(tl[1] < br[1])
- {
+ {
ntl[1] = expandr.miny;
nbr[1] = expandr.maxy;
}
else
{
ntl[1] = expandr.maxy;
- nbr[1] = expandr.miny;
+ nbr[1] = expandr.miny;
}
-
+
//now expand the window as needed
Vector temp = ntl-tl;
-
+
//pixel offset
nl = (int)(temp[0]/pw)-1;
nt = (int)(temp[1]/ph)-1;
-
+
temp = nbr - br;
nr = (int)(temp[0]/pw)+1;
nb = (int)(temp[1]/ph)+1;
-
+
nw = renddesc.get_w() + nr - nl;
nh = renddesc.get_h() + nb - nt;
-
- //synfig::warning("Spherize: Setting subwindow (%d,%d) (%d,%d) (%d,%d)",nl,nt,nr,nb,nw,nh);
+
+ //synfig::warning("Spherize: Setting subwindow (%d,%d) (%d,%d) (%d,%d)",nl,nt,nr,nb,nw,nh);
r.set_subwindow(nl,nt,nw,nh);
-
+
/*r = renddesc;
nw = r.get_w(), nh = r.get_h();
nl = 0, nt = 0;*/
}
-
+
//synfig::warning("Spherize: render background");
if(!context.accelerated_render(&background,quality,r,cb))
{
synfig::warning("SphereDistort: Layer below failed");
return false;
}
-
+
//now distort and check to make sure we aren't overshooting our bounds here
int w = renddesc.get_w(), h = renddesc.get_h();
surface->set_wh(w,h);
-
+
Point sample = tl, sub = tl, trans(0,0);
float xs = 0,ys = 0;
int y=0,x=0;
Real invpw = 1/pw, invph = 1/ph;
Surface::pen p = surface->begin();
-
+
Point rtl = r.get_tl();
-
+
//synfig::warning("Spherize: About to transform");
-
+
for(y = 0; y < h; ++y, sample[1] += ph, p.inc_y())
{
sub = sample;
xs = (trans[0]-rtl[0])*invpw;
ys = (trans[1]-rtl[1])*invph;
-
+
if(!(xs >= 0 && xs < nw && ys >= 0 && ys < nh))
{
//synfig::warning("Spherize: we failed to account for %f,%f",xs,ys);
p.put_value(context.get_color(trans));//Color::alpha());
continue;
}
-
- //sample at that pixel location based on the quality
+
+ //sample at that pixel location based on the quality
if(quality <= 4) //cubic
{
p.put_value(background.cubic_sample(xs,ys));
}
p.dec_x(w);
}
-
- return true;
+
+ return true;
}
#endif
etl::handle<const Layer_SphereDistort> layer;
public:
Spherize_Trans(const Layer_SphereDistort* x):Transform(x->get_guid()),layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
return sphtrans(x,layer->center,layer->radius,-layer->percent,layer->type);
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
return sphtrans(x,layer->center,layer->radius,layer->percent,layer->type);
default:
break;
}
-
+
return bounds;
}
/* === T Y P E D E F S ===================================================== */
/* === C L A S S E S & S T R U C T S ======================================= */
-namespace synfig
+namespace synfig
{
class Spherize_Trans;
{
SYNFIG_LAYER_MODULE_EXT
friend class Spherize_Trans;
-
+
private:
Vector center;
void sync();
public:
-
+
Layer_SphereDistort();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
-
+
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Rect get_bounding_rect()const;
-
+
virtual Vocab get_param_vocab()const;
virtual etl::handle<synfig::Transform> get_transform()const;
}; // END of class Layer_SphereDistort
{
}
-
+
bool
Layer_Stretch::set_param(const String & param, const ValueBase &value)
{
IMPORT(amount);
IMPORT(center);
-
- return false;
+
+ return false;
}
ValueBase
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Layer_Stretch::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("amount")
.set_local_name(_("Amount"))
);
ret.push_back(ParamDesc("center")
.set_local_name(_("Center"))
);
-
+
return ret;
}
etl::handle<const Layer_Stretch> layer;
public:
Stretch_Trans(const Layer_Stretch* x):Transform(x->get_guid()),layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
return Vector((x[0]-layer->center[0])*layer->amount[0]+layer->center[0],(x[1]-layer->center[1])*layer->amount[1]+layer->center[1]);
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
return Vector((x[0]-layer->center[0])/layer->amount[0]+layer->center[0],(x[1]-layer->center[1])/layer->amount[1]+layer->center[1]);
{
SYNFIG_LAYER_MODULE_EXT
friend class ::Stretch_Trans;
-
+
private:
Vector amount;
Point center;
public:
-
+
Layer_Stretch();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
-
+
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
-
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+
virtual Vocab get_param_vocab()const;
virtual etl::handle<synfig::Transform> get_transform()const;
}; // END of class Layer_Stretch
IMPORT(height);
IMPORT(scanline);
IMPORT(alpha_aware);
-
+
return false;
}
EXPORT(height);
EXPORT(scanline);
EXPORT(alpha_aware);
-
+
EXPORT_NAME();
EXPORT_VERSION();
// don't bother supersampling if our quality is too low.
if(quality>=10)
return context.accelerated_render(surface,quality,renddesc,cb);
-
+
RendDesc desc(renddesc);
SuperCallback subcb(cb,1,9000,10000);
}
}
}
-
+
if(cb && !cb->amount_complete(10000,10000)) return false;
-
+
return true;
}
ret.push_back(ParamDesc("alpha_aware")
.set_local_name(_("Be Alpha Safe"))
);
-
+
return ret;
}
bool scanline,alpha_aware;
public:
SuperSample();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
Layer_TimeLoop::get_param_vocab()const
{
Layer::Vocab ret(Layer::get_param_vocab());
-
+
ret.push_back(ParamDesc("start_time")
.set_local_name(_("Start Time"))
);
ret.push_back(ParamDesc("end_time")
.set_local_name(_("End Time"))
);
-
+
return ret;
}
public:
~Layer_TimeLoop();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
- virtual synfig::ValueBase get_param(const synfig::String & param)const;
+ virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual Vocab get_param_vocab()const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
Translate::~Translate()
{
}
-
+
bool
Translate::set_param(const String & param, const ValueBase &value)
{
IMPORT(origin);
-
+
return false;
}
EXPORT(origin);
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Translate::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("origin")
.set_local_name(_("Origin"))
.set_description(_("Point where you want the origin to be"))
);
-
+
return ret;
}
etl::handle<const Translate> layer;
public:
Translate_Trans(const Translate* x):Transform(x->get_guid()),layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
return x+layer->origin;
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
return x-layer->origin;
using namespace etl;
class Translate_Trans;
-
+
class Translate : public Layer
{
SYNFIG_LAYER_MODULE_EXT
public:
Translate();
~Translate();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
virtual Vocab get_param_vocab()const;
virtual synfig::Rect get_full_bounding_rect(Context context)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual etl::handle<synfig::Transform> get_transform()const;
};
distort_outside(false)
{
}
-
+
bool
Twirl::set_param(const String & param, const ValueBase &value)
{
IMPORT(rotations);
IMPORT(distort_inside);
IMPORT(distort_outside);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(rotations);
EXPORT(distort_inside);
EXPORT(distort_outside);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
+
return false;
}
Twirl::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("center")
.set_local_name(_("Center"))
);
-
+
ret.push_back(ParamDesc("radius")
.set_local_name(_("Radius"))
.set_description(_("This is the radius of the circle"))
{
Point centered(pos-center);
Real mag(centered.mag());
-
+
Angle a;
if((distort_inside || mag>radius) && (distort_outside || mag<radius))
a=rotations*((centered.mag()-radius)/radius);
else
return pos;
-
+
if(reverse) a=-a;
-
- const Real sin(Angle::sin(a).get());
- const Real cos(Angle::cos(a).get());
+
+ const Real sin(Angle::sin(a).get());
+ const Real cos(Angle::cos(a).get());
Point twirled;
twirled[0]=cos*centered[0]-sin*centered[1];
etl::handle<const Twirl> layer;
public:
Twirl_Trans(const Twirl* x):Transform(x->get_guid()),layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
return layer->distort(x,true);
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
return layer->distort(x,false);
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
{
SYNFIG_LAYER_MODULE_EXT
friend class Twirl_Trans;
-
+
private:
synfig::Point center;
synfig::Point distort(const synfig::Point &pos, bool reverse=false)const;
public:
-
+
Twirl();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
//virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
-
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+
virtual Vocab get_param_vocab()const;
virtual etl::handle<synfig::Transform> get_transform()const;
}; // END of class Twirl
cache_e=(-dest_tl[1]+dest_tr[1])/(src_br[0]-src_tl[0]);
cache_f=(-dest_tl[1]+dest_bl[1])/(src_br[1]-src_tl[1]);
cache_i=(dest_tl[1]-dest_tr[1]+dest_br[1]-dest_bl[1])/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
- cache_j=dest_tl[1];
+ cache_j=dest_tl[1];
*/
-
+
/* matrix[2][0]=(dest_tl[0]-dest_tr[0]+dest_br[0]-dest_bl[0])/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
matrix[2][1]=(dest_tl[1]-dest_tr[1]+dest_br[1]-dest_bl[1])/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
matrix[2][2]=quad_area(dest_tl,dest_tr,dest_br,dest_bl)/((src_br[1]-src_tl[1])*(src_br[0]-src_tl[0]));
-
+
matrix[0][0]=-(-dest_tl[1]+dest_tr[1])/(src_br[0]-src_tl[0]);
matrix[0][1]=-(-dest_tl[1]+dest_bl[1])/(src_br[1]-src_tl[1]);
const Real& y1(min(src_br[1],src_tl[1]));
const Real& x2(max(src_br[0],src_tl[0]));
const Real& y2(max(src_br[1],src_tl[1]));
-
+
Real tx1(dest_bl[0]);
Real ty1(dest_bl[1]);
Real tx2(dest_br[0]);
matrix[2][2] = 1.0;
}
#undef matrix
-
+
Real scaletrans[3][3]={
{ scalex, 0, -x1*scalex },
{ 0, scaley, -y1*scaley },
IMPORT_PLUS(dest_br,sync());
IMPORT(clip);
IMPORT(horizon);
-
+
return false;
}
EXPORT(dest_br);
EXPORT(clip);
EXPORT(horizon);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Warp::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("src_tl")
.set_local_name(_("Source TL"))
.set_box("src_br")
etl::handle<const Warp> layer;
public:
Warp_Trans(const Warp* x):Transform(x->get_guid()),layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
return layer->transform_backward(x);
//Point pos(x-layer->origin);
//return Point(layer->cos_val*pos[0]-layer->sin_val*pos[1],layer->sin_val*pos[0]+layer->cos_val*pos[1])+layer->origin;
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
if(!rect.is_inside(newpos))
return 0;
}
-
+
return context.hit_check(newpos);
}
Real pw=(renddesc.get_w())/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
Real ph=(renddesc.get_h())/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
-
+
if(cb && !cb->amount_complete(0,10000))
return false;
-
+
Point tl(renddesc.get_tl());
Point br(renddesc.get_br());
Rect bounding_rect;
-
+
Rect render_rect(tl,br);
Rect clip_rect(Rect::full_plane());
Rect dest_rect(dest_tl,dest_br); dest_rect.expand(dest_tr).expand(dest_bl);
surface->clear();
return true;
}
-
+
{
Rect other(render_rect);
if(clip)
other&=dest_rect;
-
+
Point min(other.get_min());
Point max(other.get_max());
-
+
bool init_point_set=false;
-
+
// Point trans_point[4];
Point p;
// Real trans_z[4];
Real z,minz(10000000000000.0f),maxz(0);
-
-
+
+
p=transform_forward(min);
z=transform_backward_z(p);
if(z>0 && z<horizon*2)
bounding_rect=Rect(p);
init_point_set=true;
maxz=std::max(maxz,z);
- minz=std::min(minz,z);
+ minz=std::min(minz,z);
}
-
+
p=transform_forward(max);
z=transform_backward_z(p);
if(z>0 && z<horizon*2)
bounding_rect=Rect(p);
init_point_set=true;
maxz=std::max(maxz,z);
- minz=std::min(minz,z);
+ minz=std::min(minz,z);
}
swap(min[1],max[1]);
bounding_rect=Rect(p);
init_point_set=true;
maxz=std::max(maxz,z);
- minz=std::min(minz,z);
+ minz=std::min(minz,z);
}
-
+
p=transform_forward(max);
z=transform_backward_z(p);
if(z>0 && z<horizon*2)
bounding_rect=Rect(p);
init_point_set=true;
maxz=std::max(maxz,z);
- minz=std::min(minz,z);
+ minz=std::min(minz,z);
}
-
+
if(!init_point_set)
{
surface->set_wh(renddesc.get_w(),renddesc.get_h());
return true;
}
zoom_factor=(1+(maxz-minz));
-
+
}
#ifdef ACCEL_WARP_IS_BROKEN
return Layer::accelerated_render(context,surface,quality,renddesc, cb);
#else
-
+
/*swap(tl[1],br[1]);
bounding_rect
.expand(transform_forward(tl))
.expand(transform_forward(br))
;
swap(tl[1],br[1]);*/
-
+
//synfig::warning("given window: [%f,%f]-[%f,%f] %dx%d",tl[0],tl[1],br[0],br[1],renddesc.get_w(),renddesc.get_h());
//synfig::warning("Projected: [%f,%f]-[%f,%f]",bounding_rect.get_min()[0],bounding_rect.get_min()[1],bounding_rect.get_max()[0],bounding_rect.get_max()[1]);
// source rectangle
if(clip)
clip_rect&=Rect(src_tl,src_br);
-
+
// Bound ourselves to the bounding rectangle of
// what is under us
clip_rect&=context.get_full_bounding_rect();//.expand_x(abs(zoom_factor/pw)).expand_y(abs(zoom_factor/ph));
bounding_rect&=clip_rect;
-
+
Point min_point(bounding_rect.get_min());
Point max_point(bounding_rect.get_max());
-
-
+
+
if(tl[0]>br[0])
{
tl[0]=max_point[0];
br[1]=max_point[1];
tl[1]=min_point[1];
}
-
-
+
+
const int tmp_d(max(renddesc.get_w(),renddesc.get_h()));
Real src_pw=(tmp_d*zoom_factor)/(br[0]-tl[0]);
Real src_ph=(tmp_d*zoom_factor)/(br[1]-tl[1]);
-
+
RendDesc desc(renddesc);
desc.clear_flags();
//desc.set_flags(RendDesc::PX_ASPECT);
src_pw=(desc.get_w())/(desc.get_br()[0]-desc.get_tl()[0]);
src_ph=(desc.get_h())/(desc.get_br()[1]-desc.get_tl()[1]);
-
+
Surface source;
source.set_wh(desc.get_w(),desc.get_h());
if(!context.accelerated_render(&source,quality,desc,&stageone))
return false;
-
+
surface->set_wh(renddesc.get_w(),renddesc.get_h());
surface->clear();
-
+
Surface::pen pen(surface->begin());
if(quality<=4)
(*surface)[y][x]=Color::alpha();
continue;
}
-
+
u=(tmp[0]-tl[0])*src_pw;
v=(tmp[1]-tl[1])*src_ph;
-
+
if(u<0 || v<0 || u>=source.get_w() || v>=source.get_h() || isnan(u) || isnan(v))
{
(*surface)[y][x]=context.get_color(tmp);
}
- else
+ else
(*surface)[y][x]=source.cubic_sample(u,v);
}
if(y&31==0 && cb)
(*surface)[y][x]=Color::alpha();
continue;
}
-
+
u=(tmp[0]-tl[0])*src_pw;
v=(tmp[1]-tl[1])*src_ph;
-
+
if(u<0 || v<0 || u>=source.get_w() || v>=source.get_h() || isnan(u) || isnan(v))
{
if(clip)
(*surface)[y][x]=Color::alpha();
continue;
}
-
+
u=(tmp[0]-tl[0])*src_pw;
v=(tmp[1]-tl[1])*src_ph;
-
+
if(u<0 || v<0 || u>=source.get_w() || v>=source.get_h() || isnan(u) || isnan(v))
{
if(clip)
synfig::Rect
Warp::get_bounding_rect()const
-{
+{
return Rect::full_plane();
}
Warp::get_full_bounding_rect(Context context)const
{
// return Rect::full_plane();
-
+
Rect under(context.get_full_bounding_rect());
if(clip)
{
under&=Rect(src_tl,src_br);
}
-
+
return get_transform()->perform(under);
-
+
/*
Rect under(context.get_full_bounding_rect());
Rect ret(Rect::zero());
-
+
if(under.area()==HUGE_VAL)
return Rect::full_plane();
-
+
ret.expand(
transform_backward(
under.get_min()
public:
void sync();
-
+
Warp();
~Warp();
-
+
virtual synfig::Rect get_full_bounding_rect(synfig::Context context)const;
virtual synfig::Rect get_bounding_rect()const;
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const synfig::String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
- virtual Vocab get_param_vocab()const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ virtual Vocab get_param_vocab()const;
virtual etl::handle<synfig::Transform> get_transform()const;
};
size(0.25,0.25)
{
}
-
+
bool
XORPattern::set_param(const String & param, const ValueBase &value)
{
{
EXPORT(pos);
EXPORT(size);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Color
return Color((Color::value_type)rindex/(Color::value_type)255.0,(Color::value_type)gindex/(Color::value_type)255.0,(Color::value_type)bindex/(Color::value_type)255.0,1.0);
}
-
+
Layer::Vocab
XORPattern::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("pos")
.set_local_name(_("Offset"))
);
.set_local_name(_("Size"))
.set_origin("pos")
);
-
+
return ret;
}
public:
XORPattern();
-
+
virtual bool set_param(const String ¶m, const ValueBase &value);
virtual ValueBase get_param(const String ¶m)const;
virtual Color get_color(Context context, const Point &pos)const;
- virtual Vocab get_param_vocab()const;
+ virtual Vocab get_param_vocab()const;
};
/* === E N D =============================================================== */
amount(0)
{
}
-
+
bool
Zoom::set_param(const String & param, const ValueBase &value)
{
IMPORT(center);
IMPORT(amount);
-
+
return false;
}
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Zoom::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("amount")
.set_local_name(_("Amount"))
.set_description(_("Amount to zoom in"))
.set_local_name(_("Center"))
.set_description(_("Point to zoom in to"))
);
-
+
return ret;
}
etl::handle<const Zoom> layer;
public:
Zoom_Trans(const Zoom* x):Transform(x->get_guid()),layer(x) { }
-
+
synfig::Vector perform(const synfig::Vector& x)const
{
return (x-layer->center)*exp(layer->amount)+layer->center;
}
-
+
synfig::Vector unperform(const synfig::Vector& x)const
{
return (x-layer->center)/exp(layer->amount)+layer->center;
Real amount;
public:
Zoom();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Vocab get_param_vocab()const;
virtual synfig::Rect get_full_bounding_rect(synfig::Context context)const;
virtual etl::handle<synfig::Transform> get_transform()const;
FILE *file=fopen(filename.c_str(),"rb");
if(!file)
{
- if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str()));
+ if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str()));
else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str()));
return false;
}
BITMAPINFOHEADER infoheader;
char b_char=fgetc(file);
char m_char=fgetc(file);
-
+
if(b_char!='B' || m_char!='M')
{
- if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),filename.c_str()));
+ if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),filename.c_str()));
else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),filename.c_str()));
return false;
}
-
+
if(fread(&fileheader.bfSize, 1, sizeof(BITMAPFILEHEADER)-4, file)!=sizeof(BITMAPFILEHEADER)-4)
{
- String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPFILEHEADER from %s"),filename.c_str()));
- if(cb)cb->error(str);
+ String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPFILEHEADER from %s"),filename.c_str()));
+ if(cb)cb->error(str);
else synfig::error(str);
return false;
}
-
+
if(fread(&infoheader, 1, sizeof(BITMAPINFOHEADER), file)!=sizeof(BITMAPINFOHEADER))
{
- String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPINFOHEADER from %s"),filename.c_str()));
- if(cb)cb->error(str);
+ String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPINFOHEADER from %s"),filename.c_str()));
+ if(cb)cb->error(str);
else synfig::error(str);
return false;
}
-
+
int offset=little_endian(fileheader.bfOffsetBits);
-
- if(offset!=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2)
+
+ if(offset!=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2)
{
- String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPFILEHEADER in %s. (bfOffsetBits=%d, should be %d)"),filename.c_str(),offset,sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2));
- if(cb)cb->error(str);
+ String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPFILEHEADER in %s. (bfOffsetBits=%d, should be %d)"),filename.c_str(),offset,sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2));
+ if(cb)cb->error(str);
else synfig::error(str);
return false;
}
if(little_endian(infoheader.biSize)!=little_endian(40))
{
- String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPINFOHEADER in %s. (biSize=%d, should be 40)"),filename.c_str(),little_endian(infoheader.biSize)));
- if(cb)cb->error(str);
+ String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPINFOHEADER in %s. (biSize=%d, should be 40)"),filename.c_str(),little_endian(infoheader.biSize)));
+ if(cb)cb->error(str);
else synfig::error(str);
return false;
}
-
+
int w,h,bit_count;
w=little_endian(infoheader.biWidth);
h=little_endian(infoheader.biHeight);
bit_count=little_endian_short(infoheader.biBitCount);
-
+
synfig::warning("w:%d\n",w);
synfig::warning("h:%d\n",h);
synfig::warning("bit_count:%d\n",bit_count);
-
+
if(little_endian(infoheader.biCompression))
{
- if(cb)cb->error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported")));
+ if(cb)cb->error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported")));
else synfig::error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported")));
return false;
}
if(bit_count!=24 && bit_count!=32)
{
- if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count));
+ if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count));
else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count));
return false;
}
-
+
int x;
int y;
surface.set_wh(w,h);
float b=gamma().b_U8_to_F32((unsigned char)fgetc(file));
float g=gamma().g_U8_to_F32((unsigned char)fgetc(file));
float r=gamma().r_U8_to_F32((unsigned char)fgetc(file));
-
+
surface[h-y-1][x]=Color(
r,
g,
if(bit_count==32)
fgetc(file);
}
-
- fclose(file);
+
+ fclose(file);
return true;
}
bmp::set_rend_desc(RendDesc *given_desc)
{
pf=PF_BGR;
-
+
// Flip the image upside down,
// because bitmaps are upside down.
given_desc->set_flags(0);
br[1]=tmp;
given_desc->set_tl(tl);
given_desc->set_br(br);
-
+
desc=*given_desc;
if(desc.get_frame_end()-desc.get_frame_start()>0)
{
}
else
multi_image=false;
-
+
return true;
}
bmp::start_frame(synfig::ProgressCallback *callback)
{
int w=desc.get_w(),h=desc.get_h();
-
+
rowspan=4*((w*(channels(pf)*8)+31)/32);
if(multi_image)
{
newfilename(filename),
ext(find(filename.begin(),filename.end(),'.'),filename.end());
newfilename.erase(find(newfilename.begin(),newfilename.end(),'.'),newfilename.end());
-
+
newfilename+=etl::strprintf("%04d",imagecount)+ext;
file=fopen(newfilename.c_str(),"wb");
if(callback)callback->task(newfilename+_(" (animated)"));
file=fopen(filename.c_str(),"wb");
if(callback)callback->task(filename);
}
-
+
if(!file)
{
if(callback)callback->error(_("Unable to open file"));
else synfig::error(_("Unable to open file"));
return false;
}
-
+
BITMAPFILEHEADER fileheader;
BITMAPINFOHEADER infoheader;
-
+
fileheader.bfType[0]='B';
fileheader.bfType[1]='M';
fileheader.bfSize=little_endian(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+rowspan*h);
- fileheader.bfReserved1=0;
- fileheader.bfReserved2=0;
- fileheader.bfOffsetBits=little_endian(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2);
-
+ fileheader.bfReserved1=0;
+ fileheader.bfReserved2=0;
+ fileheader.bfOffsetBits=little_endian(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2);
+
infoheader.biSize=little_endian(40);
infoheader.biWidth=little_endian(w);
infoheader.biHeight=little_endian(h);
infoheader.biYPelsPerMeter=little_endian((int)rend_desc().get_y_res()); // pels per meter...?
infoheader.biClrUsed=little_endian(0);
infoheader.biClrImportant=little_endian(0);
-
+
fprintf(file,"BM");
-
+
if(!fwrite(&fileheader.bfSize,sizeof(BITMAPFILEHEADER)-4,1,file))
{
if(callback)callback->error(_("Unable to write file header to file"));
delete [] buffer;
buffer=new unsigned char[rowspan];
-
+
delete [] color_buffer;
color_buffer=new Color[desc.get_w()];
{
if(!file)
return false;
-
+
convert_color_format(buffer, color_buffer, desc.get_w(), pf, gamma());
-
+
if(!fwrite(buffer,1,rowspan,file))
return false;
bool
dv_trgt::set_rend_desc(RendDesc *given_desc)
-{
+{
// Set the aspect ratio
if(wide_aspect)
{
// 16:9 Aspect
given_desc->set_wh(160,90);
-
+
// Widescreen should be progressive scan
given_desc->set_interlaced(false);
}
{
// 4:3 Aspect
given_desc->set_wh(400,300);
-
+
// We should be interlaced
given_desc->set_interlaced(true);
}
-
+
// but the pixel res should be 720x480
given_desc->clear_flags(),given_desc->set_wh(720,480);
-
+
// NTSC Frame rate is 29.97
given_desc->set_frame_rate(29.97);
-
+
// The pipe to encodedv is PPM, which needs RGB data
//given_desc->set_pixel_format(PF_RGB);
-
+
// Set the description
desc=*given_desc;
-
+
return true;
}
dv_trgt::init()
{
imagecount=desc.get_frame_start();
-
+
string command;
-
+
if(wide_aspect)
command=strprintf("encodedv -w 1 - > \"%s\"\n",filename.c_str());
else
command=strprintf("encodedv - > \"%s\"\n",filename.c_str());
-
+
// Open the pipe to encodedv
file=popen(command.c_str(),"w");
-
+
if(!file)
{
synfig::error(_("Unable to open pipe to encodedv"));
}
// Sleep for a moment to let the pipe catch up
- etl::clock().sleep(0.25f);
+ etl::clock().sleep(0.25f);
return true;
}
dv_trgt::start_frame(synfig::ProgressCallback *callback)
{
int w=desc.get_w(),h=desc.get_h();
-
+
if(!file)
return false;
-
+
fprintf(file, "P6\n");
fprintf(file, "%d %d\n", w, h);
- fprintf(file, "%d\n", 255);
-
+ fprintf(file, "%d\n", 255);
+
delete [] buffer;
buffer=new unsigned char[3*w];
delete [] color_buffer;
color_buffer=new Color[w];
-
+
return true;
}
return false;
convert_color_format(buffer, color_buffer, desc.get_w(), PF_RGB, gamma());
-
+
if(!fwrite(buffer,1,desc.get_w()*3,file))
return false;
-
+
return true;
}
public:
dv_trgt(const char *filename);
virtual ~dv_trgt();
-
+
virtual bool set_rend_desc(synfig::RendDesc *desc);
virtual bool init();
{
if(file)
{
- pclose(file);
+ pclose(file);
}
string command;
-
+
command=strprintf("ffmpeg -i \"%s\" -an -f image2pipe -vcodec ppm -\n",filename.c_str());
-
+
file=popen(command.c_str(),"r");
-
+
if(!file)
{
cerr<<"Unable to open pipe to ffmpeg"<<endl;
}
cur_frame=-1;
}
-
+
while(cur_frame<frame-1)
{
cerr<<"Seeking to..."<<frame<<'('<<cur_frame<<')'<<endl;
char cookie[2];
cookie[0]=fgetc(file);
cookie[1]=fgetc(file);
-
+
if(cookie[0]!='P' || cookie[1]!='6')
{
cerr<<"stream not in PPM format \""<<cookie[0]<<cookie[1]<<'"'<<endl;
return false;
}
-
+
fgetc(file);
fscanf(file,"%d %d\n",&w,&h);
fscanf(file,"%f",&divisor);
fgetc(file);
-
+
if(feof(file))
return false;
-
+
int x;
int y;
frame.set_wh(w,h);
1.0
);
}
- cur_frame++;
+ cur_frame++;
return true;
}
ffmpeg_mptr::~ffmpeg_mptr()
{
if(file)
- pclose(file);
+ pclose(file);
#ifdef HAVE_TERMIOS_H
tcsetattr(0,TCSANOW,&oldtty);
#endif
if(!grab_frame());
return false;
}
-
+
surface=frame;
return false;
}
bool seek_to(int frame);
bool grab_frame(void);
-
+
public:
ffmpeg_mptr(const char *filename);
~ffmpeg_mptr();
ffmpeg_trgt::set_rend_desc(RendDesc *given_desc)
{
//given_desc->set_pixel_format(PF_RGB);
-
+
// Make sure that the width and height
// are multiples of 8
given_desc->set_w((given_desc->get_w()+4)/8*8);
if(fps>=59.94)
given_desc->set_frame_rate(59.94);
*/
-
+
desc=*given_desc;
return true;
if(desc.get_frame_end()-desc.get_frame_start()>0)
multi_image=true;
string command;
-
+
command=strprintf("ffmpeg -f image2pipe -vcodec ppm -an -r %f -i pipe: -loop -hq -title \"%s\" -vcodec mpeg1video -y \"%s\"\n",desc.get_frame_rate(),get_canvas()->get_name().c_str(),filename.c_str());
-
+
file=popen(command.c_str(),"w");
-
+
// etl::yield();
-
+
if(!file)
{
synfig::error(_("Unable to open pipe to ffmpeg"));
return false;
}
-
+
return true;
}
ffmpeg_trgt::start_frame(synfig::ProgressCallback *callback)
{
int w=desc.get_w(),h=desc.get_h();
-
+
if(!file)
return false;
-
+
fprintf(file, "P6\n");
fprintf(file, "%d %d\n", w, h);
- fprintf(file, "%d\n", 255);
-
+ fprintf(file, "%d\n", 255);
+
delete [] buffer;
buffer=new unsigned char[3*w];
delete [] color_buffer;
color_buffer=new Color[w];
-
+
return true;
}
{
if(!file)
return false;
-
+
convert_color_format(buffer, color_buffer, desc.get_w(), PF_RGB, gamma());
if(!fwrite(buffer,1,desc.get_w()*3,file))
return false;
-
+
return true;
}
virtual void end_frame();
virtual ~ffmpeg_trgt();
-
+
virtual synfig::Color * start_scanline(int scanline);
virtual bool end_scanline();
};
{
EXPORT(size);
EXPORT(type);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Color
Blur_Layer::get_color(Context context, const Point &pos)const
{
Point blurpos = Blur(size,type)(pos);
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
return context.get_color(blurpos);
// int x,y;
SuperCallback stageone(cb,0,5000,10000);
SuperCallback stagetwo(cb,5000,10000,10000);
-
+
const int w = renddesc.get_w(),
h = renddesc.get_h();
const Real pw = renddesc.get_pw(),
ph = renddesc.get_ph();
-
+
RendDesc workdesc(renddesc);
Surface worksurface,blurred;
-
+
//callbacks depend on how long the blur takes
if(size[0] || size[1])
{
if(type == Blur::DISC)
{
stageone = SuperCallback(cb,0,5000,10000);
- stagetwo = SuperCallback(cb,5000,10000,10000);
+ stagetwo = SuperCallback(cb,5000,10000,10000);
}
else
{
stageone = SuperCallback(cb,0,9000,10000);
- stagetwo = SuperCallback(cb,9000,10000,10000);
+ stagetwo = SuperCallback(cb,9000,10000,10000);
}
}
else
{
stageone = SuperCallback(cb,0,9999,10000);
- stagetwo = SuperCallback(cb,9999,10000,10000);
+ stagetwo = SuperCallback(cb,9999,10000,10000);
}
-
+
//expand the working surface to accommodate the blur
-
+
//the expanded size = 1/2 the size in each direction rounded up
int halfsizex = (int) (abs(size[0]*.5/pw) + 3),
halfsizey = (int) (abs(size[1]*.5/ph) + 3);
-
+
//expand by 1/2 size in each direction on either side
switch(type)
{
#define GAUSSIAN_ADJUSTMENT (0.05)
Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
-
+
pw=pw*pw;
ph=ph*ph;
halfsizex = (halfsizex + 1)/2;
halfsizey = (halfsizey + 1)/2;
workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey );
-
+
break;
}
}
-
+
//render the background onto the expanded surface
if(!context.accelerated_render(&worksurface,quality,workdesc,&stageone))
return false;
//blur the image
Blur(size,type,&stagetwo)(worksurface,workdesc.get_br()-workdesc.get_tl(),blurred);
-
+
//be sure the surface is of the correct size
surface->set_wh(renddesc.get_w(),renddesc.get_h());
-
+
{
Surface::pen pen(surface->begin());
worksurface.blit_to(pen,halfsizex,halfsizey,renddesc.get_w(),renddesc.get_h());
//if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
return true;
}
-
+
Layer::Vocab
Blur_Layer::get_param_vocab(void)const
{
.add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
.add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
);
-
+
return ret;
}
return context.get_full_bounding_rect();
Rect bounds(context.get_full_bounding_rect().expand_x(size[0]).expand_y(size[1]));
-
+
return bounds;
}
public:
Blur_Layer();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
{
Color ret(in);
Real brightness((this->brightness-0.5)*this->contrast+0.5);
-
+
if(gamma.get_gamma_r()!=1.0)
{
if(ret.get_r() < 0)
ret.set_r(-gamma.r_F32_to_F32(-ret.get_r()));
}else
{
- ret.set_r(gamma.r_F32_to_F32(ret.get_r()));
- }
+ ret.set_r(gamma.r_F32_to_F32(ret.get_r()));
+ }
}
if(gamma.get_gamma_g()!=1.0)
{
ret.set_g(-gamma.g_F32_to_F32(-ret.get_g()));
}else
{
- ret.set_g(gamma.g_F32_to_F32(ret.get_g()));
- }
+ ret.set_g(gamma.g_F32_to_F32(ret.get_g()));
+ }
}
if(gamma.get_gamma_b()!=1.0)
{
ret.set_b(-gamma.b_F32_to_F32(-ret.get_b()));
}else
{
- ret.set_b(gamma.b_F32_to_F32(ret.get_b()));
- }
+ ret.set_b(gamma.b_F32_to_F32(ret.get_b()));
+ }
}
-
+
assert(!isnan(ret.get_r()));
assert(!isnan(ret.get_g()));
assert(!isnan(ret.get_b()));
-
+
if(exposure!=0.0)
{
const float factor(exp(exposure));
ret.set_g(ret.get_g()*factor);
ret.set_b(ret.get_b()*factor);
}
-
+
// Adjust Contrast
if(contrast!=1.0)
{
ret.set_g(ret.get_g()*contrast);
ret.set_b(ret.get_b()*contrast);
}
-
+
if(brightness)
{
// Adjust R Channel Brightness
ret.set_r(ret.get_r()-brightness);
else
ret.set_r(0);
-
+
// Adjust G Channel Brightness
if(ret.get_g()>-brightness)
ret.set_g(ret.get_g()+brightness);
ret.set_g(ret.get_g()-brightness);
else
ret.set_g(0);
-
+
// Adjust B Channel Brightness
if(ret.get_b()>-brightness)
ret.set_b(ret.get_b()+brightness);
else
ret.set_b(0);
}
-
+
// Return the color, adjusting the hue if necessary
if(!!hue_adjust)
return ret.rotate_uv(hue_adjust);
else
return ret;
}
-
+
bool
Layer_ColorCorrect::set_param(const String & param, const ValueBase &value)
{
{
gamma.set_gamma(1.0/value.get(Real()));
return true;
- }
- return false;
+ }
+ return false;
}
ValueBase
EXPORT_NAME();
EXPORT_VERSION();
-
- return ValueBase();
+
+ return ValueBase();
}
Layer::Vocab
Layer_ColorCorrect::get_param_vocab()const
{
Layer::Vocab ret;
-
+
ret.push_back(ParamDesc("hue_adjust")
.set_local_name(_("Hue Adjust"))
);
ret.push_back(ParamDesc("gamma")
.set_local_name(_("Gamma Adjustment"))
);
-
+
return ret;
}
{
return correct_color(context.get_color(pos));
}
-
+
bool
Layer_ColorCorrect::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
class Layer_ColorCorrect : public Layer
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
Angle hue_adjust;
Color correct_color(const Color &in)const;
public:
-
+
Layer_ColorCorrect();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual Rect get_full_bounding_rect(Context context)const;
-
+
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
-
+
virtual Vocab get_param_vocab()const;
}; // END of class Layer_ColorCorrect
Halftone::operator()(const Point &point, const float& luma, float supersample)const
{
float halftone(mask(point));
-
+
if(supersample>=0.5f)
supersample=0.4999999999f;
-
+
halftone=(halftone-0.5f)*(1.0f-supersample*2.0f)+0.5f;
-
+
const float diff(halftone-luma);
-
+
if(supersample)
{
const float amount(diff/(supersample*2.0f)+0.5f);
{
float radius1;
float radius2;
-
+
point-=offset;
{
const float a(Angle::sin(-angle).get()), b(Angle::cos(-angle).get());
const float u(point[0]),v(point[1]);
-
+
point[0]=b*u-a*v;
point[1]=a*u+b*v;
}
x*=2;
return x;
}
-
+
{
Point pnt(fmod(point[0],size[0]),fmod(point[1],size[1]));
while(pnt[0]<0)pnt[0]+=abs(size[0]);
pnt*=2.0;
pnt[0]/=size[0];
pnt[1]/=size[1];
-
+
radius1=pnt.mag()/SQRT2;
radius1*=radius1;
}
if(type==TYPE_DARKONLIGHT || type== TYPE_LIGHTONDARK)
return radius1;
-
+
{
Point pnt(fmod(point[0]+size[0]*0.5,size[0]),fmod(point[1]+size[0]*0.5,size[1]));
while(pnt[0]<0)pnt[0]+=abs(size[0]);
pnt*=2.0;
pnt[0]/=size[0];
pnt[1]/=size[1];
-
+
radius2=pnt.mag()/SQRT2;
radius2*=radius2;
}
-
+
if(type==TYPE_DIAMOND)
{
//return (radius1+(1.0f-radius2))*0.5;
x-=0.5;
x*=2.0;
if(x<0)x=-sqrt(-x);else x=sqrt(x);
- x*=1.01f;
+ x*=1.01f;
x/=2.0;
x+=0.5;
return x;
}
-
+
if(type==TYPE_SYMMETRIC)
{
float x(((radius2-radius1)*((radius1+(1.0f-radius2))*0.5)+radius1)*2.0f);
x-=0.5;
x*=2.0;
if(x<0)x=-sqrt(-x);else x=sqrt(x);
- x*=1.01f;
+ x*=1.01f;
x/=2.0;
x+=0.5;
return x;
synfig::Angle angle;
float mask(synfig::Point point)const;
-
+
float operator()(const synfig::Point &point, const float& intensity, float supersample=0)const;
};
halftone.size=(synfig::Vector(0.25,0.25));
halftone.angle=(Angle::zero());
halftone.type=TYPE_SYMMETRIC;
-
+
set_blend_method(Color::BLEND_STRAIGHT);
}
else if(amount>=1.0f)
halfcolor=color_light;
else
- halfcolor=Color::blend(color_light,color_dark,amount,Color::BLEND_STRAIGHT);
-
+ halfcolor=Color::blend(color_light,color_dark,amount,Color::BLEND_STRAIGHT);
+
halfcolor.set_a(color.get_a());
return halfcolor;
IMPORT_AS(halftone.type,"type");
IMPORT_AS(halftone.angle,"angle");
IMPORT_AS(halftone.offset,"offset");
-
- return Layer_Composite::set_param(param,value);
+
+ return Layer_Composite::set_param(param,value);
}
ValueBase
EXPORT(color_dark);
EXPORT(color_light);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
Halftone2::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("offset")
.set_local_name(_("Mask Offset"))
.set_is_distance()
.add_enum_value(TYPE_DIAMOND,"diamond",_("Diamond"))
.add_enum_value(TYPE_STRIPE,"stripe",_("Stripe"))
);
-
+
return ret;
}
return false;
if(get_amount()==0)
return true;
-
+
const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
const Point tl(renddesc.get_tl());
const int w(surface->get_w());
Surface::pen pen(surface->begin());
Point pos;
int x,y;
-
+
if(is_solid_color())
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
)
);
}
-
+
// Mark our progress as finished
if(cb && !cb->amount_complete(10000,10000))
return false;
public:
Halftone2();
-
+
virtual bool set_param(const synfig::String ¶m, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String ¶m)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Vocab get_param_vocab()const;
};
color[1]=Color::green();
color[2]=Color::blue();
}
-
+
set_blend_method(Color::BLEND_STRAIGHT);
for(int i=0;i<3;i++)
tone[i].size=size;
tone[i].type=type;
}
-
+
#define matrix inverse_matrix
//float matrix[3][3];
-
+
if(subtractive)
{
for(int i=0;i<3;i++)
}
#undef matrix
-
-
+
+
#if 0
// Insert guass-jordan elimination code here
int k=0,i=0,j=0,z_size=3;
#define A inverse_matrix
-
- for (k=0;k<z_size;k++)
- // the pivot element
- { A[k][k]= -1/A[k][k];
-
+
+ for (k=0;k<z_size;k++)
+ // the pivot element
+ { A[k][k]= -1/A[k][k];
+
//the pivot column
- for (i=0;i<z_size;i++)
+ for (i=0;i<z_size;i++)
if (i!=k) A[i][k]*=A[k][k];
//elements not in a pivot row or column
for (i=0;i<z_size;i++)
- if (i!=k)
+ if (i!=k)
for (j=0;j<z_size;j++)
if (j!=k)
A[i][j]+=A[i][k]*A[k][j];
//elements in a pivot row
for (i=0;i<z_size;i++)
- if (i!=k)
+ if (i!=k)
A[k][i]*=A[k][k];
}
//change sign
for (i=0;i<z_size;i++) /*reverse sign*/
for (j=0;j<z_size;j++)
- A[i][j]=-A[i][j];
+ A[i][j]=-A[i][j];
#undef A
#endif
}
Color halfcolor;
float chan[3];
-
-
+
+
if(subtractive)
{
chan[0]=inverse_matrix[0][0]*(1.0f-in_color.get_r())+inverse_matrix[0][1]*(1.0f-in_color.get_g())+inverse_matrix[0][2]*(1.0f-in_color.get_b());
halfcolor-=(~color[0])*tone[0](point,chan[0],supersample);
halfcolor-=(~color[1])*tone[1](point,chan[1],supersample);
halfcolor-=(~color[2])*tone[2](point,chan[2],supersample);
-
+
halfcolor.set_a(in_color.get_a());
}
else
halfcolor+=color[0]*tone[0](point,chan[0],supersample);
halfcolor+=color[1]*tone[1](point,chan[1],supersample);
halfcolor+=color[2]*tone[2](point,chan[2],supersample);
-
+
halfcolor.set_a(in_color.get_a());
}
IMPORT_PLUS(color[0],sync());
IMPORT_PLUS(color[1],sync());
IMPORT_PLUS(color[2],sync());
-
+
IMPORT_PLUS(subtractive,sync());
-
+
IMPORT(tone[0].angle);
IMPORT(tone[0].offset);
IMPORT(tone[2].angle);
IMPORT(tone[2].offset);
-
- return Layer_Composite::set_param(param,value);
+
+ return Layer_Composite::set_param(param,value);
}
ValueBase
EXPORT(color[2]);
EXPORT(subtractive);
-
+
EXPORT(tone[0].angle);
EXPORT(tone[0].offset);
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
ret.push_back(ParamDesc("subtractive")
.set_local_name(_("Subtractive Flag"))
);
-
+
for(int i=0;i<3;i++)
{
String chan_name(strprintf("Chan%d",i));
-
+
ret.push_back(ParamDesc(strprintf("color[%d]",i))
.set_local_name(chan_name+_(" Color"))
);
.set_origin(strprintf("tone[%d].offset",i))
);
}
-
+
return ret;
}
return false;
if(get_amount()==0)
return true;
-
+
const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
const Point tl(renddesc.get_tl());
const int w(surface->get_w());
Surface::pen pen(surface->begin());
Point pos;
int x,y;
-
+
if(is_solid_color())
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
)
);
}
-
+
// Mark our progress as finished
if(cb && !cb->amount_complete(10000,10000))
return false;
float calc_supersample(const synfig::Point &x, float pw,float ph)const;
//float halftone_func(synfig::Point x)const;
-
+
void sync();
public:
Halftone3();
-
+
virtual bool set_param(const synfig::String ¶m, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String ¶m)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Vocab get_param_vocab()const;
};
bool
LumaKey::set_param(const String ¶m, const ValueBase &value)
-{
+{
return Layer_Composite::set_param(param,value);
}
{
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
LumaKey::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
/* ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
.set_description(_("Color of checkers"))
LumaKey::get_color(Context context, const Point &getpos)const
{
const Color color(context.get_color(getpos));
-
+
if(get_amount()==0.0)
return color;
-
+
Color ret(color);
ret.set_a(ret.get_y()*ret.get_a());
ret.set_y(1);
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
return ret;
{
if(is_disabled())
return Rect::zero();
-
+
return context.get_full_bounding_rect();
}
public:
LumaKey();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual Vocab get_param_vocab()const;
synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
IMPORT(origin);
IMPORT(size);
IMPORT(fade_out);
-
- return Layer_Composite::set_param(param,value);
+
+ return Layer_Composite::set_param(param,value);
}
ValueBase
EXPORT(origin);
EXPORT(size);
EXPORT(fade_out);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
RadialBlur::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("origin")
.set_local_name(_("Origin"))
.set_description(_("Point where you want the origin to be"))
ret.push_back(ParamDesc("fade_out")
.set_local_name(_("Fade Out"))
);
-
+
return ret;
}
{
if(cb && !cb->amount_complete(0,10000))
return false;
-
+
Surface tmp_surface;
-
+
if(!context.accelerated_render(surface,quality,renddesc,cb))
return false;
tmp_surface=*surface;
-
+
int x,y;
const Point tl(renddesc.get_tl());
apen.set_alpha(get_amount());
apen.set_blend_method(get_blend_method());
-
+
int steps(5);
-
+
if(quality>=9)steps=20;
else if(quality>=5)steps=30;
else if(quality>=4)steps=60;
else if(quality>=3)steps=100;
else steps=120;
-
+
Surface::value_prep_type cooker;
-
+
for(y=0,pos[1]=tl[1];y<h;y++,apen.inc_y(),apen.dec_x(x),pos[1]+=ph)
for(x=0,pos[0]=tl[0];x<w;x++,apen.inc_x(),pos[0]+=pw)
{
Color pool(Color::alpha());
int poolsize(0);
-
+
int x0(round_to_int(begin[0])),
y0(round_to_int(begin[1])),
x1(round_to_int(end[0])),
y1(round_to_int(end[1]));
-
+
int i;
int steep = 1;
int sx, sy; /* step positive or negative (1 or -1) */
int dx, dy; /* delta (difference in X and Y between points) */
int e;
int w(tmp_surface.get_w()),h(tmp_surface.get_h());
-
+
dx = abs(x1 - x0);
sx = ((x1 - x0) > 0) ? 1 : -1;
dy = abs(y1 - y0);
poolsize+=1;
}
}
-
+
while (e >= 0)
{
y0 += sy;
Point begin,end;
begin=pos;
end=(pos-origin)*(1.0f-size)+origin;
-
+
Color pool(Color::alpha());
float f,poolsize(0);
int i;
{
Point loc((end-begin)*f+begin-tl);
loc[0]/=pw;loc[1]/=ph;
-
+
if(fade_out)
pool+=tmp_surface.linear_sample(loc[0],loc[1])*(i-steps),poolsize+=(i-steps);
else
public:
RadialBlur();
~RadialBlur();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const synfig::String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- virtual Vocab get_param_vocab()const;
+ virtual Vocab get_param_vocab()const;
};
/* === E N D =============================================================== */
IMPORT(pos[0]);
IMPORT(pos[1]);
IMPORT(size);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(color);
EXPORT(pos);
EXPORT(pos[0]);
- EXPORT(pos[1]);
+ EXPORT(pos[1]);
EXPORT(size);
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
CheckerBoard::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
.set_description(_("Color of checkers"))
public:
CheckerBoard();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual Vocab get_param_vocab()const;
synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
{
constructcache();
}
-
+
bool
Circle::ImportParameters(const String ¶m, const ValueBase &value)
{
IMPORT(invert);
IMPORT(pos);
IMPORT(falloff);
-
+
return Layer_Composite::set_param(param,value);
}
constructcache();
return true;
}
-
+
return false;
}
EXPORT_NAME();
EXPORT_VERSION();
-
+
return Layer_Composite::get_param(param);
}
Circle::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
);
);
ret.push_back(ParamDesc("pos")
.set_local_name(_("Center"))
- );
+ );
ret.push_back(ParamDesc("invert")
.set_local_name(_("Invert"))
.set_description(_("Invert the circle"))
.add_enum_value(FALLOFF_SIGMOND,"sigmond",_("Sigmond"))
.add_enum_value(FALLOFF_COSINE,"cosine",_("Cosine"))
);
-
+
return ret;
}
if(get_amount()==0)
return context.hit_check(point);
-
+
bool in_circle(temp.mag_squared() <= radius*radius);
if(invert)
if(get_amount()-(feather/radius)<=0.0)
in_circle=false;
}
-
+
if(in_circle)
{
synfig::Layer::Handle tmp;
return context.hit_check(point);
}
-//falloff functions
+//falloff functions
Real Circle::SqdFalloff(const Circle::CircleDataCache &c, const Real &mag_sqd)
{
//squared proportional falloff
return 1.0 - (c.outer_radius_sqd - mag_sqd) / c.diff_sqd;
}
-
+
Real Circle::SqrtFalloff(const Circle::CircleDataCache &c, const Real &mag_sqd)
{
//linear distance falloff
ret = 1.0 - sqrt(ret);
return ret;
}
-
+
Real Circle::LinearFalloff(const Circle::CircleDataCache &c, const Real &mag_sqd)
{
//linear distance falloff
return 1.0 - ( c.outer_radius - sqrt(mag_sqd) ) / c.double_feather;
//linear distance falloff
}
-
+
Real Circle::SigmondFalloff(const Circle::CircleDataCache &c, const Real &mag_sqd)
{
//linear distance falloff
cache.inner_radius = radius - feather;
if(cache.inner_radius < 0)
cache.inner_radius = 0;
-
+
cache.outer_radius = radius + feather;
-
+
cache.inner_radius_sqd = cache.inner_radius > 0 ? (radius-feather)*(radius-feather) : 0;
cache.outer_radius_sqd = (radius+feather)*(radius+feather);
-
+
cache.diff_sqd = feather*feather*4.0;
cache.double_feather = feather*2.0;
-
+
falloff_func = GetFalloffFunc();
}
Circle::FALLOFF_FUNC *Circle::GetFalloffFunc()const
{
switch(falloff)
- {
+ {
case FALLOFF_SQUARED: return invert?InvSqdFalloff:SqdFalloff;
-
+
case FALLOFF_SQRT: return invert?InvSqrtFalloff:SqrtFalloff;
-
+
case FALLOFF_INTERPOLATION_LINEAR: return invert?InvLinearFalloff:LinearFalloff;
-
+
case FALLOFF_SIGMOND: return invert?InvSigmondFalloff:SigmondFalloff;
case FALLOFF_COSINE:
if(radius==0 || is_disabled())
return context.get_color(point);
-
+
Point temp=pos-point;
-
+
/*const Real inner_radius = radius-feather;
const Real outer_radius = radius+feather;
-
+
const Real inner_radius_sqd = inner_radius > 0 ? (radius-feather)*(radius-feather) : 0;
const Real outer_radius_sqd = (radius+feather)*(radius+feather);
-
+
const Real diff_radii_sqd = outer_radius_sqd - inner_radius_sqd;
const Real double_feather = feather*2.0;*/
-
+
/*const Real &inner_radius = cache.inner_radius;
const Real &outer_radius = cache.outer_radius;*/
-
+
const Real &inner_radius_sqd = cache.inner_radius_sqd;
const Real &outer_radius_sqd = cache.outer_radius_sqd;
-
+
/*const Real &diff_radii_sqd = cache.diff_radii_sqd;
const Real &double_feather = cache.double_feather;*/
-
+
const Vector::value_type mag_squared = temp.mag_squared();
-
+
//Outside the circle, with feathering enabled
if( mag_squared > outer_radius_sqd )
{
// inverted -> outside == colored in
if(invert)
- {
+ {
if(get_amount() == 1 && get_blend_method() == Color::BLEND_STRAIGHT)
return color;
else
else
return context.get_color(point);
}
-
+
//inside the circle's solid area (with feathering)
else if(mag_squared <= inner_radius_sqd)
{
else
return context.get_color(point);
}
-
+
//If we get here, the pixel is within the feathering area, and is thus subject to falloff
else
{
Color::value_type alpha;
-
+
/*switch(falloff)
{
-
+
case FALLOFF_SQUARED:
//squared proportional falloff
alpha = (outer_radius_sqd - mag_squared) / diff_radii_sqd;
break;
-
+
case FALLOFF_SQRT:
//linear distance falloff
alpha = ( outer_radius - sqrt(mag_squared) ) / double_feather;
//then take the square root of it
alpha = sqrt(alpha);
break;
-
+
case FALLOFF_INTERPOLATION_LINEAR:
//linear distance falloff
alpha = ( outer_radius - sqrt(mag_squared) ) / double_feather;
break;
-
+
case FALLOFF_SIGMOND:
default:
//linear distance falloff
alpha = 1.0 / (1 + exp(-(alpha*10-5)) );
break;
}
-
+
//If we're inverted, we need to invert the falloff value
if(invert)
alpha=1.0-alpha;*/
-
+
alpha = falloff_func(cache,mag_squared);
-
+
//Compose falloff value with amount from the composite layer, and that is the blend value
alpha *= get_amount();
-
+
return Color::blend(color,context.get_color(point),alpha,get_blend_method());
}
}
bool
Circle::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
-{
+{
// trivial case
if(is_disabled() || (radius==0 && invert==false))
return context.accelerated_render(surface,quality, renddesc, cb);
const Point br(renddesc.get_br());
const int w(renddesc.get_w());
const int h(renddesc.get_h());
-
+
const Real x_neg = tl[0] > br[0] ? -1 : 1;
const Real y_neg = tl[1] > br[1] ? -1 : 1;
-
+
// Width and Height of a pixel
const Real pw = (br[0] - tl[0]) / w;
const Real ph = (br[1] - tl[1]) / h;
-
+
// Increasing the feather amount by the size of
// a pixel will create an anti-aliased appearance
const Real newfeather=feather + (abs(ph)+abs(pw))/4.0;
-
+
//int u,v;
int left = (int) floor( (pos[0] - x_neg*(radius+newfeather) - tl[0]) / pw );
int right = (int) ceil( (pos[0] + x_neg*(radius+newfeather) - tl[0]) / pw );
int top = (int) floor( (pos[1] - y_neg*(radius+newfeather) - tl[1]) / ph );
int bottom = (int) ceil( (pos[1] + y_neg*(radius+newfeather) - tl[1]) / ph );
-
+
//clip the rectangle bounds
if(left < 0)
left = 0;
right = w-1;
if(bottom >= h)
bottom = h-1;
-
+
const Real inner_radius = radius-newfeather>0 ? radius-newfeather : 0;
const Real outer_radius = radius+newfeather;
-
+
const Real inner_radius_sqd = inner_radius*inner_radius;
const Real outer_radius_sqd = outer_radius*outer_radius;
-
+
const Real diff_radii_sqd = 4*newfeather*std::max(newfeather,radius);//4.0*radius*newfeather;
const Real double_feather = newfeather * 2.0;
-
+
//Compile the temporary cache for the falloff calculations
FALLOFF_FUNC *func = GetFalloffFunc();
-
- const CircleDataCache cache =
+
+ const CircleDataCache cache =
{
inner_radius,outer_radius,
inner_radius_sqd,outer_radius_sqd,
diff_radii_sqd,double_feather
- };
-
+ };
+
//info("Circle: Initialized everything");
-
+
//let the rendering begin
SuperCallback supercb(cb,0,9000,10000);
-
+
//if it's a degenerate circle, do what we need to do, and then leave
if(left >= right || top >= bottom)
{
if(invert)
- {
+ {
if(get_amount() == 1 && get_blend_method() == Color::BLEND_STRAIGHT)
{
surface->set_wh(w,h);
{
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
- }
-
+ }
+
Surface::alpha_pen p(surface->begin(),get_amount(),_BlendFunc(get_blend_method()));
-
+
p.set_value(color);
p.put_block(h,w);
return true;
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
- return true;
+ return true;
}
}
-
+
if( (pos[0] - tl[0])*(pos[0] - tl[0]) + (pos[1] - tl[1])*(pos[1] - tl[1]) < inner_radius_sqd
&& (pos[0] - br[0])*(pos[0] - br[0]) + (pos[1] - br[1])*(pos[1] - br[1]) < inner_radius_sqd
&& (pos[0] - tl[0])*(pos[0] - tl[0]) + (pos[1] - br[1])*(pos[1] - br[1]) < inner_radius_sqd
surface->set_wh(w,h);
surface->fill(color);
return true;
- }
- }
+ }
+ }
}
-
- //info("Circle: Non degenerate, rasterize %c", invert);
+
+ //info("Circle: Non degenerate, rasterize %c", invert);
//we start in the middle of the left-top pixel
Real leftf = (left + 0.5)*pw + tl[0];
Real topf = (top + 0.5)*ph + tl[1];
-
+
//the looping variables
Real x,y;
int i,j;
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
//make topf and leftf relative to the center of the circle
leftf -= pos[0];
topf -= pos[1];
-
+
j = top;
y = topf;
-
+
//Loop over the valid y-values in the bounding square
for(;j <= bottom; j++, y += ph)
{
i = left;
x = leftf;
-
+
//for each y-value, Loop over the bounding x-values in the bounding square
for(;i <= right; i++, x += pw)
{
//for each pixel, figure out the distance and blend
Real r = x*x + y*y;
-
+
//if in the inner circle then the full color shows through
if(r <= inner_radius_sqd)
{
case FALLOFF_SQUARED:
myamount = (outer_radius_sqd - r) / diff_radii_sqd;
break;
-
+
case FALLOFF_SQRT:
myamount = (outer_radius - sqrt(r)) / double_feather;
myamount = sqrt(myamount);
break;
-
+
case FALLOFF_INTERPOLATION_LINEAR:
myamount = (outer_radius - sqrt(r)) / double_feather;
break;
-
+
case FALLOFF_SIGMOND:
default:
myamount = (outer_radius - sqrt(r)) / double_feather;
myamount = 1.0 / ( 1 + exp(-(myamount*10 - 5)) );
break;
}*/
-
+
Real myamount = func(cache,r);
//if(myamount<0.0)myamount=0.0;
//if(myamount>1.0)myamount=1.0;
myamount *= get_amount();
(*surface)[j][i] = Color::blend(color,(*surface)[j][i],myamount,get_blend_method());
- }
+ }
}
}
}
Surface background;
RendDesc desc(renddesc);
desc.set_flags(0);
-
+
int offset_x=0,offset_y=0;
-
+
//fill the surface with the background color initially
surface->set_wh(w,h);
surface->fill(color);
-
+
//then render the background to an alternate surface
if(get_amount() == 1 && get_blend_method() == Color::BLEND_STRAIGHT)
{
offset_x = left;
offset_y = top;
-
+
//if there is no background showing through we are done
if(right < left || bottom < top)
return true;
-
+
desc.set_subwindow(left,top,right-left+1,bottom-top+1);
-
+
// Render what is behind us
if(!context.accelerated_render(&background,quality,desc,&supercb))
{
right = w-1;
top = 0;
bottom = h-1;
-
+
leftf = /*0.5*pw +*/ tl[0];
topf = /*0.5*ph +*/ tl[1];
-
+
// Render what is behind us
if(!context.accelerated_render(&background,quality,renddesc,&supercb))
{
return false;
}
}
-
+
topf -= pos[1];
leftf-= pos[0];
-
+
j = top;
y = topf;
-
+
for(;j <= bottom; j++, y+=ph)
{
i = left;
x = leftf;
-
+
for(;i <= right; i++, x+=pw)
- {
+ {
Vector::value_type r = x*x + y*y;
-
+
if(r < inner_radius_sqd)
{
(*surface)[j][i] = background[j-offset_y][i-offset_x];
amount = 1.0 - ( 1.0/( 1 + exp(-(amount*10-5)) ) );
break;
}*/
-
+
Real amount = func(cache,r);
-
+
if(amount<0.0)amount=0.0;
if(amount>1.0)amount=1.0;
-
+
amount*=get_amount();
-
+
(*surface)[j][i]=Color::blend(color,background[j-offset_y][i-offset_x],amount,get_blend_method());
}else if(get_amount() != 1 || get_blend_method() != Color::BLEND_STRAIGHT)
{
- (*surface)[j][i]=Color::blend(color,background[j][i],get_amount(),get_blend_method());
- }
+ (*surface)[j][i]=Color::blend(color,background[j][i],get_amount(),get_blend_method());
+ }
}
}
}
);
return bounds & context.get_full_bounding_rect();
}
- return Rect::full_plane();
+ return Rect::full_plane();
}
return Layer_Composite::get_full_bounding_rect(context);
{
Real inner_radius;
Real outer_radius;
-
+
Real inner_radius_sqd;
Real outer_radius_sqd;
-
+
Real diff_sqd;
Real double_feather;
};
-
+
typedef Real FALLOFF_FUNC(const CircleDataCache &c, const Real &mag_sqd);
-
+
FALLOFF_FUNC *falloff_func;
CircleDataCache cache;
void constructcache();
static Real SqdFalloff(const CircleDataCache &c, const Real &mag_sqd);
- static Real InvSqdFalloff(const CircleDataCache &c, const Real &mag_sqd);
+ static Real InvSqdFalloff(const CircleDataCache &c, const Real &mag_sqd);
static Real SqrtFalloff(const CircleDataCache &c, const Real &mag_sqd);
- static Real InvSqrtFalloff(const CircleDataCache &c, const Real &mag_sqd);
+ static Real InvSqrtFalloff(const CircleDataCache &c, const Real &mag_sqd);
static Real LinearFalloff(const CircleDataCache &c, const Real &mag_sqd);
- static Real InvLinearFalloff(const CircleDataCache &c, const Real &mag_sqd);
+ static Real InvLinearFalloff(const CircleDataCache &c, const Real &mag_sqd);
static Real SigmondFalloff(const CircleDataCache &c, const Real &mag_sqd);
static Real InvSigmondFalloff(const CircleDataCache &c, const Real &mag_sqd);
static Real CosineFalloff(const CircleDataCache &c, const Real &mag_sqd);
- static Real InvCosineFalloff(const CircleDataCache &c, const Real &mag_sqd);
-
+ static Real InvCosineFalloff(const CircleDataCache &c, const Real &mag_sqd);
+
FALLOFF_FUNC *GetFalloffFunc()const;
bool ImportParameters(const String ¶m, const ValueBase &value);
FALLOFF_SIGMOND =3,
FALLOFF_SQRT =4
};
-
+
Circle();
-
+
virtual bool set_param(const String ¶m, const ValueBase &value);
-
+
virtual ValueBase get_param(const String ¶m)const;
-
+
virtual Color get_color(Context context, const Point &pos)const;
-
+
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
virtual synfig::Rect get_full_bounding_rect(synfig::Context context)const;
virtual synfig::Rect get_bounding_rect()const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
-
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+
virtual Vocab get_param_vocab()const;
};
/* === P R O C E D U R E S ================================================= */
-// This function was adapted from what was
+// This function was adapted from what was
// described on http://www.whisqu.se/per/docs/math28.htm
Point line_intersection(
const Point& p1,
const float x3(p2[0]+t2[0]);
const float y3(p2[1]+t2[1]);
-
+
const float near_infinity((float)1e+10);
-
+
float m1,m2; // the slopes of each line
-
+
// compute slopes, note the cludge for infinity, however, this will
// be close enough
-
+
if ((x1-x0)!=0)
m1 = (y1-y0)/(x1-x0);
else
m1 = near_infinity;
-
+
if ((x3-x2)!=0)
m2 = (y3-y2)/(x3-x2);
else
m2 = near_infinity;
-
+
// compute constants
const float& a1(m1);
const float& a2(m2);
const float b2(-1.0f);
const float c1(y0-m1*x0);
const float c2(y2-m2*x2);
-
+
// compute the inverse of the determinate
const float det_inv(1.0f/(a1*b2 - a2*b1));
-
- // use Kramers rule to compute the intersection
+
+ // use Kramers rule to compute the intersection
return Point(
((b1*c2 - b2*c1)*det_inv),
((a2*c1 - a1*c2)*det_inv)
expand=0;
homogeneous_width=true;
clear();
-
+
vector<BLinePoint> bline_point_list;
bline_point_list.push_back(BLinePoint());
bline_point_list.push_back(BLinePoint());
bline_point_list.push_back(BLinePoint());
- bline_point_list[0].set_vertex(Point(0,1));
- bline_point_list[1].set_vertex(Point(0,-1));
+ bline_point_list[0].set_vertex(Point(0,1));
+ bline_point_list[1].set_vertex(Point(0,-1));
bline_point_list[2].set_vertex(Point(1,0));
- bline_point_list[0].set_tangent(bline_point_list[1].get_vertex()-bline_point_list[2].get_vertex()*0.5f);
- bline_point_list[1].set_tangent(bline_point_list[2].get_vertex()-bline_point_list[0].get_vertex()*0.5f);
- bline_point_list[2].set_tangent(bline_point_list[0].get_vertex()-bline_point_list[1].get_vertex()*0.5f);
- bline_point_list[0].set_width(1.0f);
- bline_point_list[1].set_width(1.0f);
- bline_point_list[2].set_width(1.0f);
+ bline_point_list[0].set_tangent(bline_point_list[1].get_vertex()-bline_point_list[2].get_vertex()*0.5f);
+ bline_point_list[1].set_tangent(bline_point_list[2].get_vertex()-bline_point_list[0].get_vertex()*0.5f);
+ bline_point_list[2].set_tangent(bline_point_list[0].get_vertex()-bline_point_list[1].get_vertex()*0.5f);
+ bline_point_list[0].set_width(1.0f);
+ bline_point_list[1].set_width(1.0f);
+ bline_point_list[2].set_width(1.0f);
bline=bline_point_list;
-
+
needs_sync=true;
}
clear();
try {
#if 1
-
+
const bool loop(bline.get_loop());
const vector<synfig::BLinePoint> bline_(bline.get_list().begin(),bline.get_list().end());
#define bline bline_
-
+
vector<BLinePoint>::const_iterator
iter,
next(bline.begin());
vector<Point>
side_a,
side_b;
-
+
if(loop)
iter=--bline.end();
else
iter=next++;
Vector last_tangent=iter->get_tangent1();
-
+
for(bool first=!loop;next!=end;iter=next++,first=false)
{
Vector prev_t(iter->get_tangent1());
Vector iter_t(iter->get_tangent2());
Vector next_t(next->get_tangent1());
-
+
bool split_flag(iter->get_split_tangent_flag());
-
+
if(iter_t.is_equal_to(Vector::zero()) && next_t.is_equal_to(Vector::zero()))
{
iter_t=next_t=next->get_vertex()-iter->get_vertex();
split_flag=true;
}
-
+
// Setup the curve
hermite<Vector> curve(
iter->get_vertex(),
iter_t,
next_t
);
-
+
const float
iter_w((iter->get_width()*width)*0.5f+expand),
next_w((next->get_width()*width)*0.5f+expand);
const derivative< hermite<Vector> > deriv(curve);
-
+
// Make cusps as necessary
if(!first && sharp_cusps && split_flag && (!prev_t.is_equal_to(iter_t) || iter_t.is_equal_to(Vector::zero())) && !last_tangent.is_equal_to(Vector::zero()))
{
Vector curr_tangent(deriv(CUSP_TANGENT_ADJUST));
-
+
const Vector t1(last_tangent.perp().norm());
const Vector t2(curr_tangent.perp().norm());
-
+
Real cross(t1*t2.perp());
Real perp((t1-t2).mag());
- if(cross>CUSP_THRESHOLD)
+ if(cross>CUSP_THRESHOLD)
{
const Point p1(iter->get_vertex()+t1*iter_w);
const Point p2(iter->get_vertex()+t2*iter_w);
-
+
side_a.push_back(line_intersection(p1,last_tangent,p2,curr_tangent));
}
else if(cross<-CUSP_THRESHOLD)
{
const Point p1(iter->get_vertex()-t1*iter_w);
const Point p2(iter->get_vertex()-t2*iter_w);
-
+
side_b.push_back(line_intersection(p1,last_tangent,p2,curr_tangent));
}
else if(cross>0 && perp>1)
float amount(max(0.0f,(float)(-cross/CUSP_THRESHOLD))*(SPIKE_AMOUNT-1)+1);
side_b.push_back(iter->get_vertex()-(t1+t2).norm()*iter_w*amount);
- }
+ }
}
-
+
// Make the outline
if(homogeneous_width)
{
side_a.push_back(p+d*w);
side_b.push_back(p-d*w);
-
+
lastpoint=p;
}
}
const Vector d(deriv(n>CUSP_TANGENT_ADJUST?n:CUSP_TANGENT_ADJUST).perp().norm());
const Vector p(curve(n));
const float w(((next_w-iter_w)*n+iter_w));
-
+
side_a.push_back(p+d*w);
side_b.push_back(p-d*w);
}
side_a.push_back(curve(1.0)+last_tangent.perp().norm()*next_w);
side_b.push_back(curve(1.0)-last_tangent.perp().norm()*next_w);
}
-
+
if(loop)
{
reverse(side_b.begin(),side_b.end());
add_polygon(side_b);
return;
}
-
+
// Insert code for adding end tip
if(round_tip[1] && !loop && side_a.size())
{
// remove the last point
side_a.pop_back();
-
+
const Point vertex(bline.back().get_vertex());
const Vector tangent(last_tangent.norm());
const float w((bline.back().get_width()*width)*0.5f+expand);
-
+
hermite<Vector> curve(
vertex+tangent.perp()*w,
vertex-tangent.perp()*w,
// remove the last point
side_a.pop_back();
}
-
+
for(;!side_b.empty();side_b.pop_back())
side_a.push_back(side_b.back());
{
// remove the last point
side_a.pop_back();
-
+
const Point vertex(bline.front().get_vertex());
const Vector tangent(bline.front().get_tangent2().norm());
const float w((bline.front().get_width()*width)*0.5f+expand);
-
+
hermite<Vector> curve(
vertex-tangent.perp()*w,
vertex+tangent.perp()*w,
// remove the last point
side_a.pop_back();
}
-
+
add_polygon(side_a);
-
-
+
+
#else
-
+
bool loop_;
if(bline.get_contained_type()==ValueBase::TYPE_BLINEPOINT)
{
}
else
loop_=value.get_loop();
-
+
segment_list=convert_bline_to_segment_list(value);
width_list=convert_bline_to_width_list(value);
}
clear();
return;
}
-
-
+
+
// Repair the width list if we need to
{
Real default_width;
default_width=0.01;
else
default_width=width_list.back();
-
+
while(width_list.size()<segment_list.size()+1)
width_list.push_back(default_width);
while(width_list.size()>segment_list.size()+1)
width_list.pop_back();
-
+
}
// Repair the zero tangents (if any)
iter->t1=iter->t2=iter->p2-iter->p1;
}
}
-
+
vector<Real>::iterator iter;
vector<Real> scaled_width_list;
for(iter=width_list.begin();iter!=width_list.end();++iter)
vector<Point> vector_list;
Vector last_tangent(segment_list.back().t2);
clear();
-
+
if(!loop_)
last_tangent=NO_LOOP_COOKIE;
-
+
{
vector<Segment>::iterator iter;
vector<Real>::iterator witer;
witer=scaled_width_list.begin();
iter!=segment_list.end();
++iter,++witer)
- {
+ {
if(iter->t1.mag_squared()<=EPSILON && iter->t2.mag_squared()<=EPSILON)
{
vector_list.push_back(iter->p1-(iter->p2-iter->p1).perp().norm()*witer[0]);
curve.p2()=iter->p2;
curve.t2()=iter->t2;
curve.sync();
-
+
etl::derivative<etl::hermite<Vector> > deriv(curve);
-
+
// without this if statement, the broken tangents would
// have boxed edges
if(sharp_cusps && last_tangent!=NO_LOOP_COOKIE && !last_tangent.is_equal_to(iter->t1))
{
//Vector curr_tangent(iter->t1);
Vector curr_tangent(deriv(CUSP_TANGENT_ADJUST));
-
+
const Vector t1(last_tangent.perp().norm());
const Vector t2(curr_tangent.perp().norm());
-
+
Point p1(iter->p1+t1*witer[0]);
Point p2(iter->p1+t2*witer[0]);
-
+
Real cross(t1*t2.perp());
-
- if(cross>CUSP_THRESHOLD)
+
+ if(cross>CUSP_THRESHOLD)
vector_list.push_back(line_intersection(p1,last_tangent,p2,curr_tangent));
else if(cross>0)
{
}
//last_tangent=iter->t2;
last_tangent=deriv(1.0f-CUSP_TANGENT_ADJUST);
-
+
for(n=0.0f;n<1.0f;n+=1.0f/SAMPLES)
vector_list.push_back(curve(n)+deriv(n>CUSP_TANGENT_ADJUST?n:CUSP_TANGENT_ADJUST).perp().norm()*((witer[1]-witer[0])*n+witer[0]) );
vector_list.push_back(curve(1.0)+deriv(1.0-CUSP_TANGENT_ADJUST).perp().norm()*witer[1]);
-
+
}
}
if(round_tip[1] && !loop_/* && (!sharp_cusps || segment_list.front().p1!=segment_list.back().p2)*/)
{
// remove the last point
vector_list.pop_back();
-
+
iter--;
curve.p1()=iter->p2+Vector(last_tangent[1],-last_tangent[0]).norm()*(*witer);
vector_list.pop_back();
}
}
-
+
if(!loop_)
last_tangent=NO_LOOP_COOKIE;
else
vector_list.clear();
last_tangent=segment_list.front().t1;
}
-
+
//else
// last_tangent=segment_list.back().t2;
-
+
{
vector<Segment>::reverse_iterator iter;
vector<Real>::reverse_iterator witer;
!(iter==segment_list.rend());
++iter,++witer)
{
-
+
if(iter->t1.mag_squared()<=EPSILON && iter->t2.mag_squared()<=EPSILON)
{
vector_list.push_back(iter->p2+(iter->p2-iter->p1).perp().norm()*witer[0]);
curve.p2()=iter->p2;
curve.t2()=iter->t2;
curve.sync();
-
+
etl::derivative<etl::hermite<Vector> > deriv(curve);
// without this if statement, the broken tangents would
{
//Vector curr_tangent(iter->t2);
Vector curr_tangent(deriv(1.0f-CUSP_TANGENT_ADJUST));
-
+
const Vector t1(last_tangent.perp().norm());
const Vector t2(curr_tangent.perp().norm());
Point p1(iter->p2-t1*witer[-1]);
Point p2(iter->p2-t2*witer[-1]);
-
+
Real cross(t1*t2.perp());
-
+
//if(last_tangent.perp().norm()*curr_tangent.norm()<-CUSP_THRESHOLD)
- if(cross>CUSP_THRESHOLD)
+ if(cross>CUSP_THRESHOLD)
vector_list.push_back(line_intersection(p1,last_tangent,p2,curr_tangent));
else if(cross>0)
{
}
//last_tangent=iter->t1;
last_tangent=deriv(CUSP_TANGENT_ADJUST);
-
+
for(n=1.0f;n>CUSP_TANGENT_ADJUST;n-=1.0f/SAMPLES)
vector_list.push_back(curve(n)-deriv(1-n>CUSP_TANGENT_ADJUST?n:1-CUSP_TANGENT_ADJUST).perp().norm()*((witer[-1]-witer[0])*n+witer[0]) );
vector_list.push_back(curve(0.0f)-deriv(CUSP_TANGENT_ADJUST).perp().norm()*witer[0]);
vector_list.pop_back();
iter--;
witer--;
-
+
curve.p1()=iter->p1+Vector(last_tangent[1],-last_tangent[0]).norm()*(*witer);
curve.p2()=iter->p1-(Vector(last_tangent[1],-last_tangent[0]).norm()*(*witer));
curve.t1()=-(curve.t2()=last_tangent/last_tangent.mag()*(*witer)*ROUND_END_FACTOR);
for(n=1.0;n>0.0;n-=1.0/SAMPLES)
vector_list.push_back(curve(n));
-
+
// remove the last point
vector_list.pop_back();
}
//synfig::info("BLEHH__________--- x:%f, y:%f",vector_list.front()[0],vector_list.front()[1]);
}
#endif
-
+
add_polygon(vector_list);
{
//if(value.get_contained_type()!=ValueBase::TYPE_BLINEPOINT)
// return false;
-
+
bline=value;
return true;
//sync();
return true;
}
-
+
if( param=="width_list" && value.same_as(width_list))
{
width_list=value;
IMPORT(loopyness);
IMPORT(expand);
IMPORT(homogeneous_width);
-
+
if(param!="vector_list")
return Layer_Polygon::set_param(param,value);
EXPORT(sharp_cusps);
EXPORT(width);
EXPORT(loopyness);
-
+
EXPORT_NAME();
EXPORT_VERSION();
std::vector<synfig::Segment> segment_list;
std::vector<synfig::Real> width_list;
-
+
bool round_tip[2];
-
+
bool sharp_cusps;
-
+
bool loop_;
synfig::Real width;
//! Updates the polygon data to match the parameters.
void sync();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual void set_time(Context context, Time time, Vector pos)const;
virtual bool set_version(const String &ver){if(ver=="0.1")old_version=true; return true;}
virtual void reset_version(){old_version=false;}
-
+
};
/* === E N D =============================================================== */
invert(false)
{
}
-
+
bool
Rectangle::set_param(const String & param, const ValueBase &value)
{
IMPORT(point2);
IMPORT(expand);
IMPORT(invert);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
Rectangle::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
);
.set_local_name(_("Point 1"))
.set_box("point2")
);
-
+
ret.push_back(ParamDesc("point2")
.set_local_name(_("Point 2"))
);
.set_is_distance()
.set_local_name(_("Expand amount"))
);
-
+
ret.push_back(ParamDesc("invert")
.set_local_name(_("Invert the rectangle"))
);
min[1]=std::min(point1[1],point2[1])-expand;
bool intersect(false);
-
+
if( pos[0]<max[0] && pos[0]>min[0] &&
pos[1]<max[1] && pos[1]>min[1] )
{
if(invert)
intersect=!intersect;
-
+
if(intersect)
{
synfig::Layer::Handle tmp;
max[1]=std::max(point1[1],point2[1])+expand;
min[0]=std::min(point1[0],point2[0])-expand;
min[1]=std::min(point1[1],point2[1])-expand;
-
+
/**************************
// This is darco's old-old-old feathered box code
-// it produces really nice feathered edges
+// it produces really nice feathered edges
if(feather!=0.0)
{
if( pos[0]<=max[0]-feather/2.0 && pos[0]>=min[0]+feather/2.0 &&
Color::unit alpha=1000000;
Color::unit alpha2=1000000;
-
+
if(max[0]-pos[0]+feather/2.0<alpha)
alpha=max[0]-pos[0]+feather/2.0;
if(pos[0]-min[0]+feather/2.0<alpha)
alpha=pos[0]-min[0]+feather/2.0;
-
+
if(max[1]-pos[1]+feather/2.0<alpha2)
alpha2=max[1]-pos[1]+feather/2.0;
if(pos[1]-min[1]+feather/2.0<alpha2)
alpha2=feather-alpha2;
alpha=sqrt(alpha*alpha+alpha2*alpha2);
-
+
if(alpha>=feather)
{
if(invert)
return Color::blend(color,context.get_color(pos),alpha,get_blend_method());
}
-
+
*****************/
if( pos[0]<max[0] && pos[0]>min[0] &&
return color;
else
return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method());
-
+
}
}
bool
Rectangle::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
-{
+{
if(is_disabled())
return context.accelerated_render(surface,quality,renddesc,cb);
const Real ph = (br[1] - tl[1]) / h;
Point max(point1),min(point2);
-
-
-
-
+
+
+
+
/*
-
+
if(invert)
{
max=context.get_bounding_rect().get_max();
min=context.get_full_bounding_rect().get_min();
}
*/
-
-
-
-
-
+
+
+
+
+
if((min[0] > max[0]) ^ (pw < 0))swap(min[0],max[0]);
if((min[1] > max[1]) ^ (ph < 0))swap(min[1],max[1]);
-
+
if(min[0] > max[0])
{
min[0]+=expand;
min[1]-=expand;
max[1]+=expand;
}
-
+
if(invert)
{
int left(floor_to_int((min[0]-tl[0])/pw));
int right(ceil_to_int((max[0]-tl[0])/pw));
int top(floor_to_int((min[1]-tl[1])/ph));
int bottom(ceil_to_int((max[1]-tl[1])/ph));
-
+
float left_edge((min[0]-tl[0])/pw-float(left));
float right_edge(float(right)-(max[0]-tl[0])/pw);
float top_edge((min[1]-tl[1])/ph-float(top));
float bottom_edge(float(bottom)-(max[1]-tl[1])/ph);
-
+
if(top<0)top=0,top_edge=0;
if(left<0)left=0,left_edge=0;
if(bottom>h)bottom=h,bottom_edge=0;
if(right>w)right=w,right_edge=0;
-
+
if(is_solid_color())
{
Surface subimage;
RendDesc desc(renddesc);
desc.set_flags(0);
-
+
//fill the surface with the background color initially
surface->set_wh(w,h);
surface->fill(color);
-
+
// Check for the case where there is nothing to render
if(right-left<=0||bottom-top<=0)
return true;
-
+
desc.set_subwindow(left,top,right-left,bottom-top);
-
+
// Render what is behind us
if(!context.accelerated_render(&subimage,quality,desc,cb))
{
if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
return false;
}
-
+
Surface::pen pen(surface->get_pen(left,top));
-
+
subimage.blit_to(pen);
}
else
}
Surface::alpha_pen surface_pen(surface->begin(),get_amount(),get_blend_method());
-
+
surface->fill(color,surface_pen,w,h);
if(subimage)
pen=Surface::alpha_pen(surface->get_pen(left,bottom-1),get_amount()*bottom_edge,get_blend_method());
surface->fill(color,pen,right-left,1);
}
-
+
if(right-1>=0 && right_edge)
{
pen=Surface::alpha_pen(surface->get_pen(right-1,top),get_amount()*right_edge,get_blend_method());
surface->fill(color,pen,1,bottom-top);
}
-
+
if(left>=0 && left_edge)
{
pen=Surface::alpha_pen(surface->get_pen(left,top),get_amount()*left_edge,get_blend_method());
surface->fill(color,pen,1,bottom-top);
}
-
+
if(top>=0 && top_edge)
{
pen=Surface::alpha_pen(surface->get_pen(left,top),get_amount()*top_edge,get_blend_method());
surface->fill(color,pen,right-left,1);
}
-
+
return true;
}
float right_edge((max[0]-tl[0])/pw-float(right));
float top_edge(float(top)-(min[1]-tl[1])/ph);
float bottom_edge((max[1]-tl[1])/ph-float(bottom));
-
+
if(top<=0)top=0,top_edge=0;
if(left<=0)left=0,left_edge=0;
if(bottom>=h)bottom=h,bottom_edge=0;
bottom = std::min(h,bottom);
right = std::min(w,right);
*/
-
+
Surface::alpha_pen pen;
// In the case where there is nothing to render...
if(right-left<0||bottom-top<0)
return true;
-
+
if(right-left>0&&bottom-top>0)
{
if(is_solid_color())
surface->fill(color,left,top,right-left,bottom-top);
else
- {
+ {
pen=Surface::alpha_pen(surface->get_pen(left,top),get_amount(),get_blend_method());
surface->fill(color,pen,right-left,bottom-top);
}
}
-
+
if(bottom<surface->get_h() && bottom_edge>=0.0001)
{
pen=Surface::alpha_pen(surface->get_pen(left,bottom),get_amount()*bottom_edge,get_blend_method());
pen=Surface::alpha_pen(surface->get_pen(right,top),get_amount()*right_edge,get_blend_method());
surface->fill(color,pen,1,bottom-top);
}
-
+
if(left>0 && left_edge>=0.0001)
{
pen=Surface::alpha_pen(surface->get_pen(left-1,top),get_amount()*left_edge,get_blend_method());
if(invert)
return Rect::full_plane();
- Point max(point1),min(point2);
+ Point max(point1),min(point2);
if((min[0] > max[0]))swap(min[0],max[0]);
- if((min[1] > max[1]))swap(min[1],max[1]);
+ if((min[1] > max[1]))swap(min[1],max[1]);
if(min[0] > max[0])
{
min[0]+=expand;
{
if(is_solid_color() && color.get_a()==0)
{
- Point max(point1),min(point2);
+ Point max(point1),min(point2);
if((min[0] > max[0]))swap(min[0],max[0]);
- if((min[1] > max[1]))swap(min[1],max[1]);
+ if((min[1] > max[1]))swap(min[1],max[1]);
if(min[0] > max[0])
{
min[0]+=expand;
return bounds & context.get_full_bounding_rect();
}
- return Rect::full_plane();
+ return Rect::full_plane();
}
return Layer_Composite::get_full_bounding_rect(context);
class Rectangle : public synfig::Layer_Composite, public synfig::Layer_NoDeform
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
synfig::Color color;
bool invert;
public:
-
+
Rectangle();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual synfig::Rect get_bounding_rect()const;
virtual synfig::Rect get_full_bounding_rect(synfig::Context context)const;
bline_point_list.push_back(BLinePoint());
bline_point_list.push_back(BLinePoint());
bline_point_list.push_back(BLinePoint());
- bline_point_list[0].set_vertex(Point(0,1));
- bline_point_list[1].set_vertex(Point(0,-1));
+ bline_point_list[0].set_vertex(Point(0,1));
+ bline_point_list[1].set_vertex(Point(0,-1));
bline_point_list[2].set_vertex(Point(1,0));
- bline_point_list[0].set_tangent(bline_point_list[1].get_vertex()-bline_point_list[2].get_vertex()*0.5f);
- bline_point_list[1].set_tangent(bline_point_list[2].get_vertex()-bline_point_list[0].get_vertex()*0.5f);
- bline_point_list[2].set_tangent(bline_point_list[0].get_vertex()-bline_point_list[1].get_vertex()*0.5f);
- bline_point_list[0].set_width(1.0f);
- bline_point_list[1].set_width(1.0f);
- bline_point_list[2].set_width(1.0f);
+ bline_point_list[0].set_tangent(bline_point_list[1].get_vertex()-bline_point_list[2].get_vertex()*0.5f);
+ bline_point_list[1].set_tangent(bline_point_list[2].get_vertex()-bline_point_list[0].get_vertex()*0.5f);
+ bline_point_list[2].set_tangent(bline_point_list[0].get_vertex()-bline_point_list[1].get_vertex()*0.5f);
+ bline_point_list[0].set_width(1.0f);
+ bline_point_list[1].set_width(1.0f);
+ bline_point_list[2].set_width(1.0f);
bline=bline_point_list;
}
clear();
return;
}
-
+
bool looped = bline.get_loop();
Vector::value_type n;
vector<Segment>::const_iterator iter=segment_list.begin();
//Vector last = iter->p1;
-
+
//make sure the shape has a clean slate for writing
//clear();
-
+
//and start off at the first point
//move_to(last[0],last[1]);
-
+
for(;iter!=segment_list.end();++iter)
{
//connect them with a line if they aren't already joined
{
line_to(iter->p1[0],iter->p1[1]);
}
-
+
//curve to the next end point
curve_to(iter->p1[0] + iter->t1[0]/3.0,iter->p1[1] + iter->t1[1]/3.0,
iter->p2[0] - iter->t2[0]/3.0,iter->p2[1] - iter->t2[1]/3.0,
iter->p2[0],iter->p2[1]);
-
+
last = iter->p2;*/
-
+
if(iter->t1.is_equal_to(Vector(0,0)) && iter->t2.is_equal_to(Vector(0,0)))
{
vector_list.push_back(iter->p2);
vector_list.push_back(curve(n));
}
}
-
+
//add a single point onto the end so it actually fits the shape, so we can be awesome...
if(!looped)
{
clear();
add_polygon(vector_list);
-
+
/*close();
endpath();*/
}
else
synfig::warning("Region::set_param(): The parameter \"segment_list\" is deprecated. Use \"bline\" instead.");
}
-
+
if( (param=="segment_list" || param=="bline") && value.get_type()==ValueBase::TYPE_LIST)
{
//if(value.get_contained_type()!=ValueBase::TYPE_BLINEPOINT)
// return false;
-
+
bline=value;
return true;
{
Angle dist_between_points(Angle::rot(1)/float(points));
std::vector<Point> vector_list;
-
+
int i;
for(i=0;i<points;i++)
{
EXPORT_VERSION();
if(param=="vector_list")
- return ValueBase();
+ return ValueBase();
return Layer_Polygon::get_param(param);
}
filename(filename_),
file( (filename=="-")?stdout:fopen(filename_,"wb") ),
imagecount(0),
-
+
lossy(true),
- multi_image(false),
+ multi_image(false),
dithering(true),
color_bits(8),
iframe_density(30),
loop_count(0x7fff),
- local_palette(true)
+ local_palette(true)
{
}
gif::init()
{
int w=desc.get_w(),h=desc.get_h();
-
+
if(!file)
{
synfig::error(strprintf(_("Unable to open \"%s\" for write access!"),filename.c_str()));
return false;
}
-
+
rootsize=color_bits; // Size of pixel bits
curr_frame.set_wh(w,h);
curr_frame.clear();
prev_frame.clear();
curr_surface.clear();
-
+
if(get_quality()>5)
lossy=true;
else
fputc(0xF0+(rootsize-1),file.get()); // flags
else
fputc((0xF0+(rootsize-1))&~(1<<7),file.get()); // flags
-
+
fputc(0,file.get()); // backgound color
fputc(0,file.get()); // Pixel Aspect Ratio
-
+
DEBUGPOINT();
-
+
if(!local_palette)
{
DEBUGPOINT();
curr_palette=Palette::grayscale(256/(1<<(8-rootsize))-1);
output_curr_palette();
}
-
+
if(loop_count && multi_image)
{
DEBUGPOINT();
fputc(33,file.get()); // 33 (hex 0x21) GIF Extension code
fputc(255,file.get()); // 255 (hex 0xFF) Application Extension Label
- fputc(11,file.get()); // 11 (hex (0x0B) Length of Application Block
+ fputc(11,file.get()); // 11 (hex (0x0B) Length of Application Block
fprintf(file.get(),"NETSCAPE2.0");
- fputc(3,file.get()); // 3 (hex 0x03) Length of Data Sub-Block
+ fputc(3,file.get()); // 3 (hex 0x03) Length of Data Sub-Block
fputc(1,file.get()); // 1 (hex 0x01)
fputc(loop_count&0x000000ff,file.get());
fputc((loop_count&0x0000ff00)>>8,file.get());
- fputc(0,file.get()); // 0 (hex 0x00) a Data Sub-block Terminator.
+ fputc(0,file.get()); // 0 (hex 0x00) a Data Sub-block Terminator.
}
DEBUGPOINT();
-
+
return true;
}
// int
// w=desc.get_w(),
// h=desc.get_h();
-
+
if(!file)
{
if(callback)callback->error(string("BUG:")+_("Description not set!"));
return false;
}
-
+
if(callback)callback->task(filename+strprintf(" %d",imagecount));
-
+
return true;
}
unsigned int value;
int
delaytime=round_to_int(100.0/desc.get_frame_rate());
-
+
bool build_off_previous(multi_image);
Palette prev_palette(curr_palette);
-
+
// Fill in the background color
if(!get_remove_alpha())
{
pen.dec_x(x);
}
}
-
+
if(local_palette)
{
curr_palette=Palette(curr_surface,256/(1<<(8-rootsize))-build_off_previous-1);
synfig::info("curr_palette.size()=%d",curr_palette.size());
}
-
+
int transparent_index(curr_palette.find_closest(Color(1,0,1,0))-curr_palette.begin());
bool has_transparency(curr_palette[transparent_index].color.get_a()<=0.00001);
-
+
if(has_transparency)
build_off_previous=false;
-
+
if(build_off_previous)
{
transparent_index=0;
has_transparency=true;
}
-
+
#define DISPOSE_UNDEFINED (0)
#define DISPOSE_NONE (1<<2)
#define DISPOSE_RESTORE_BGCOLOR (2<<2)
gec_flags|=DISPOSE_RESTORE_PREVIOUS;
if(has_transparency)
gec_flags|=1;
-
+
// output the Graphic Control Extension
fputc(0x21,file.get()); // Extension introducer
fputc(0xF9,file.get()); // Graphic Control Label
fputc((delaytime&0x0000ff00)>>8,file.get()); // Delay Time (LSB)
fputc(transparent_index,file.get()); // Transparent Color Index
fputc(0,file.get()); // Block Terminator
-
+
// output the image header
fputc(',',file.get());
fputc(0,file.get()); // image left
else
fputc(0x00+ rootsize-1,file.get()); // flags
-
+
if(local_palette)
{
Palette out(curr_palette);
-
+
if(build_off_previous)
curr_palette.insert(curr_palette.begin(),Color(1,0,1,0));
output_curr_palette();
curr_palette=out;
}
-
+
bs=bitstream(file);
// Prepare ourselves for LZW compression
nextcode=(1<<rootsize)+2;
table=lzwcode::NewTable((1<<rootsize));
node=table;
-
+
// Output the rootsize
fputc(rootsize,file.get()); // rootsize;
for(int cur_scanline=0;cur_scanline<desc.get_h();cur_scanline++)
{
//convert_color_format(curr_frame[cur_scanline], curr_surface[cur_scanline], desc.get_w(), PF_GRAY, gamma());
-
+
// Now we compress it!
for(i=0;i<w;i++)
{
Color color(curr_surface[cur_scanline][i].clamped());
Palette::iterator iter(curr_palette.find_closest(color));
-
+
if(dithering)
{
Color error(color-iter->color);
if(curr_surface.get_w()>i+1)
curr_surface[cur_scanline][i+1] += error * ((float)7/(float)16);
}
-
+
curr_frame[cur_scanline][i]=iter-curr_palette.begin();
-
+
value=curr_frame[cur_scanline][i];
if(build_off_previous)
value++;
if(value>(unsigned)(1<<rootsize)-1)
value=(1<<rootsize)-1;
-
+
// If the pixel is the same as the one that
// is already there, then we should make it
// transparent
{
if(lossy)
{
-
+
// Lossy
if(
abs( ( iter->color-prev_palette[prev_frame[cur_scanline][i]-1].color ).get_y() ) > (1.0/16.0) ||
else
{
// lossless version
- if(value!=prev_frame[cur_scanline][i])
+ if(value!=prev_frame[cur_scanline][i])
prev_frame[cur_scanline][i]=value;
else
value=0;
node->AddNode(nextcode, value);
bs.push_value(node->code, codesize);
node = table->FindCode(value);
-
+
// Check to see if we need to increase the codesize
if (nextcode == ( 1 << codesize))
codesize += 1;
-
+
nextcode += 1;
-
+
// check to see if we have filled up the table
if (nextcode == 4096)
{
// output the clear code: make sure to use the current
// codesize
bs.push_value((unsigned) 1 << rootsize, codesize);
-
+
delete table;
table = lzwcode::NewTable((1<<rootsize));
codesize = rootsize + 1;
nextcode = (1 << rootsize) + 2;
-
+
// since we have a new table, need the correct prefix
node = table->FindCode(value);
}
// Push the last code onto the bitstream
bs.push_value(node->code,codesize);
-
+
// Push a end-of-stream code onto the bitstream
bs.push_value((1<<rootsize)+1,codesize);
-
+
// Make sure everything is dumped out
bs.dump();
-
+
delete table;
-
+
fputc(0,file.get()); // Block terminator
fflush(file.get());
bitstream(synfig::SmartFILE file):file(file),pool(0),curr_bit(0),curr_pos(0) {}
unsigned char buffer[256];
int curr_pos;
-
+
// Pushes a single bit onto the bit
void push_bit(bool bit)
{
if(curr_bit==8)
empty();
}
-
+
// Emptys out the current pool into
// the buffer. Calls 'dump()' if the
// buffer is full.
pool=0;
if(curr_pos==255)dump();
}
-
+
// If there is anything in the
- // buffer or in the pool, it
+ // buffer or in the pool, it
// dumps it to the filestream.
// Buffer and pool are cleared.
void dump()
curr_pos=0;
}
}
-
+
// Pushes a symbol of the given size
// onto the bitstream.
void push_value(int value, int size)
int code; // lzwcode
struct lzwcode* kids; // children of this node
struct lzwcode* next; // siblings of this node
-
+
lzwcode():value(0),code(0),kids(0),next(0) { }
-
+
lzwcode *FindCode(int value)
{
lzwcode *node=this;
-
+
// check the children (kids) of the node for the value
for (node = node->kids; node != 0; node = node->next)
if (node->value == value)
return(node);
return(0);
}
-
+
void AddNode(unsigned short code, unsigned short value)
{
lzwcode *n = new lzwcode;
-
+
// add a new child to node; the child will have code and value
n->value = value;
n->code = code;
n->next = this->kids;
this->kids = n;
}
-
+
static lzwcode * NewTable(int values)
{
int i;
lzwcode * table = new lzwcode;
-
+
table->kids = 0;
for (i = 0; i < values; i++)
table->AddNode( i, i);
-
+
return(table);
}
-
+
// Destructor just deletes any
// children and sibblings.
~lzwcode()
bitstream bs;
synfig::String filename;
synfig::SmartFILE file;
- int
+ int
i, // General-purpose index
codesize, // Current code size
rootsize, // Size of pixel bits (will be recalculted)
nextcode; // Next code to use
lzwcode *table,*next,*node;
-
+
synfig::Surface curr_surface;
etl::surface<unsigned char> curr_frame;
etl::surface<unsigned char> prev_frame;
int iframe_density;
int loop_count;
bool local_palette;
-
+
synfig::Palette curr_palette;
-
+
void output_curr_palette();
-
+
public:
gif(const char *filename);
virtual void end_frame();
virtual ~gif();
-
+
virtual synfig::Color * start_scanline(int scanline);
virtual bool end_scanline(void);
symmetric(false)
{
}
-
+
bool
ConicalGradient::set_param(const String & param, const ValueBase &value)
{
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
ConicalGradient::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("gradient")
.set_local_name(_("Gradient"))
);
ret.push_back(ParamDesc("center")
.set_local_name(_("Center"))
);
-
+
ret.push_back(ParamDesc("angle")
.set_local_name(_("Angle"))
.set_origin("center")
ret.push_back(ParamDesc("symmetric")
.set_local_name(_("Symmetric"))
);
-
+
return ret;
}
Angle::rot a=Angle::tan(-centered[1],centered[0]).mod();
a+=angle;
Real dist(a.mod().get());
-
+
dist-=floor(dist);
if(symmetric)
ConicalGradient::get_color(Context context, const Point &pos)const
{
const Color color(color_func(pos));
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
return color;
else
return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method());
}
-
+
bool
ConicalGradient::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
if(quality<9)
class ConicalGradient : public synfig::Layer_Composite, public synfig::Layer_NoDeform
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
synfig::Gradient gradient;
float calc_supersample(const synfig::Point &x, float pw,float ph)const;
public:
-
+
ConicalGradient();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Vocab get_param_vocab()const;
}; // END of class ConicalGradient
{
std::vector<synfig::BLinePoint>::const_iterator iter,next,ret;
std::vector<synfig::BLinePoint>::const_iterator end(bline.end());
-
+
float dist(0);
-
+
next=bline.begin();
-
+
//if(loop)
// iter=--bline.end();
//else
iter=next++;
-
+
for(;next!=end;iter=next++)
{
// Setup the curve
{
std::vector<synfig::BLinePoint>::const_iterator iter,next,ret;
std::vector<synfig::BLinePoint>::const_iterator end(bline.end());
-
+
ret=bline.end();
float dist(100000000000.0);
-
+
next=bline.begin();
float best_bline_dist(0);
float best_bline_len(0);
float total_bline_dist(0);
etl::hermite<Vector> best_curve;
-
+
if(loop)
iter=--bline.end();
else
iter=next++;
Point bp;
-
+
for(;next!=end;iter=next++)
{
// Setup the curve
/*
const float t(curve.find_closest(p,6,0.01,0.99));
- bp=curve(t);if((bp-p).mag_squared()<dist) { ret=iter; dist=(bp-p).mag_squared(); ret_t=t; }
+ bp=curve(t);if((bp-p).mag_squared()<dist) { ret=iter; dist=(bp-p).mag_squared(); ret_t=t; }
*/
float thisdist(0);
//len=calculate_distance(*iter,*next);
len=curve.length();
}
-
+
#define POINT_CHECK(x) bp=curve(x); thisdist=(bp-p).mag_squared(); if(thisdist<dist) { ret=iter; dist=thisdist; best_bline_dist=total_bline_dist; best_bline_len=len; best_curve=curve; }
POINT_CHECK(0.0001);
*bline_dist_ret=best_bline_dist+best_curve.find_distance(0,best_curve.find_closest(p));
// *bline_dist_ret=best_bline_dist+best_curve.find_closest(p)*best_bline_len;
}
-
+
return ret;
}
bline.push_back(BLinePoint());
bline.push_back(BLinePoint());
bline.push_back(BLinePoint());
- bline[0].set_vertex(Point(0,1));
- bline[1].set_vertex(Point(0,-1));
+ bline[0].set_vertex(Point(0,1));
+ bline[1].set_vertex(Point(0,-1));
bline[2].set_vertex(Point(1,0));
- bline[0].set_tangent(bline[1].get_vertex()-bline[2].get_vertex()*0.5f);
- bline[1].set_tangent(bline[2].get_vertex()-bline[0].get_vertex()*0.5f);
- bline[2].set_tangent(bline[0].get_vertex()-bline[1].get_vertex()*0.5f);
- bline[0].set_width(1.0f);
- bline[1].set_width(1.0f);
- bline[2].set_width(1.0f);
+ bline[0].set_tangent(bline[1].get_vertex()-bline[2].get_vertex()*0.5f);
+ bline[1].set_tangent(bline[2].get_vertex()-bline[0].get_vertex()*0.5f);
+ bline[2].set_tangent(bline[0].get_vertex()-bline[1].get_vertex()*0.5f);
+ bline[0].set_width(1.0f);
+ bline[1].set_width(1.0f);
+ bline[2].set_width(1.0f);
bline_loop=true;
-
+
sync();
}
Real dist;
float perp_dist;
-
+
if(bline.size()==0)
return Color::alpha();
else if(bline.size()==1)
else
{
Point point(point_-offset);
-
+
std::vector<synfig::BLinePoint>::const_iterator iter,next;
-
+
// Figure out the BLinePoints we will be using,
// Taking into account looping.
if(perpendicular)
}
iter=next++;
if(next==bline.end()) next=bline.begin();
-
+
// Setup the curve
etl::hermite<Vector> curve(
iter->get_vertex(),
iter->get_tangent2(),
next->get_tangent1()
);
-
+
// Setup the derivative function
etl::derivative<etl::hermite<Vector> > deriv(curve);
-
+
int search_iterations(7);
-
+
/*if(quality==0)search_iterations=8;
else if(quality<=2)search_iterations=10;
else if(quality<=4)search_iterations=8;
if(quality>7)
search_iterations=4;
}
-
+
// Figure out the closest point on the curve
const float t(curve.find_closest(point,search_iterations));
-
-
+
+
// Calculate our values
p1=curve(t);
tangent=deriv(t).norm();
-
+
if(perpendicular)
{
tangent*=curve_length_;
{
thickness=(next->get_width()-iter->get_width())*t+iter->get_width();
}
- //}
+ //}
}
-
+
if(!perpendicular)
{
dist=((point_-offset)*diff-p1*diff);
}
}
-
+
if(loop)
dist-=floor(dist);
-
+
if(zigzag)
{
dist*=2.0;
}
//IMPORT(p1);
//IMPORT(p2);
-
-
+
+
IMPORT(offset);
IMPORT(perpendicular);
IMPORT(gradient);
IMPORT(loop);
IMPORT(zigzag);
- return Layer_Composite::set_param(param,value);
+ return Layer_Composite::set_param(param,value);
}
ValueBase
EXPORT(zigzag);
EXPORT(width);
EXPORT(perpendicular);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
ret.push_back(ParamDesc("perpendicular")
.set_local_name(_("Perpendicular"))
);
-
+
return ret;
}
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
public:
CurveGradient();
-
+
virtual bool set_param(const String ¶m, const ValueBase &value);
virtual ValueBase get_param(const String ¶m)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Vocab get_param_vocab()const;
};
LinearGradient::color_func(const Point &point, float supersample)const
{
Real dist(point*diff-p1*diff);
-
+
if(loop)
dist-=floor(dist);
-
+
if(zigzag)
{
dist*=2.0;
}
//IMPORT(p1);
//IMPORT(p2);
-
-
+
+
IMPORT(gradient);
IMPORT(loop);
IMPORT(zigzag);
- return Layer_Composite::set_param(param,value);
+ return Layer_Composite::set_param(param,value);
}
ValueBase
EXPORT(gradient);
EXPORT(loop);
EXPORT(zigzag);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
LinearGradient::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("p1")
.set_local_name(_("Point 1"))
.set_connect("p2")
ret.push_back(ParamDesc("zigzag")
.set_local_name(_("ZigZag"))
);
-
+
return ret;
}
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
public:
LinearGradient();
-
+
virtual bool set_param(const String ¶m, const ValueBase &value);
virtual ValueBase get_param(const String ¶m)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual Vocab get_param_vocab()const;
};
zigzag(false)
{
}
-
+
bool
RadialGradient::set_param(const String & param, const ValueBase &value)
{
IMPORT(radius);
IMPORT(loop);
IMPORT(zigzag);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(radius);
EXPORT(loop);
EXPORT(zigzag);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
RadialGradient::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("gradient")
.set_local_name(_("Gradient"))
);
ret.push_back(ParamDesc("center")
.set_local_name(_("Center"))
);
-
+
ret.push_back(ParamDesc("radius")
.set_local_name(_("Radius"))
.set_description(_("This is the radius of the circle"))
ret.push_back(ParamDesc("zigzag")
.set_local_name(_("Zig-Zag"))
);
-
+
return ret;
}
RadialGradient::color_func(const Point &point, float supersample)const
{
Real dist((point-center).mag()/radius);
-
+
if(zigzag)
{
dist*=2.0;
return pool.demult_alpha();
}
}
-
+
return gradient(dist,supersample);
}
else
return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method());
}
-
+
bool
RadialGradient::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
class RadialGradient : public synfig::Layer_Composite, public synfig::Layer_NoDeform
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
synfig::Gradient gradient;
float calc_supersample(const synfig::Point &x, float pw,float ph)const;
public:
-
+
RadialGradient();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
-
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+
virtual Vocab get_param_vocab()const;
}; // END of class RadialGradient
clockwise(false)
{
}
-
+
bool
SpiralGradient::set_param(const String & param, const ValueBase &value)
{
IMPORT(radius);
IMPORT(angle);
IMPORT(clockwise);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(radius);
EXPORT(angle);
EXPORT(clockwise);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
SpiralGradient::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("gradient")
.set_local_name(_("Gradient"))
);
ret.push_back(ParamDesc("center")
.set_local_name(_("Center"))
);
-
+
ret.push_back(ParamDesc("radius")
.set_local_name(_("Radius"))
.set_description(_("This is the radius of the circle"))
ret.push_back(ParamDesc("clockwise")
.set_local_name(_("Clockwise"))
);
-
+
return ret;
}
Angle a;
a=Angle::tan(-centered[1],centered[0]).mod();
a=a+angle;
-
+
if(supersample<0.00001)supersample=0.00001;
-
+
Real dist((pos-center).mag()/radius);
if(clockwise)
dist+=Angle::rot(a.mod()).get();
else
dist-=Angle::rot(a.mod()).get();
-
+
dist-=floor(dist);
if(dist+supersample*0.5>1.0)
{
pool+=gradient(1.0-(dist-supersample*0.5),supersample*0.5).premult_alpha()*(-(dist-supersample*0.5));
return pool.demult_alpha();
}
-
+
return gradient(dist,supersample);
}
SpiralGradient::get_color(Context context, const Point &pos)const
{
const Color color(color_func(pos));
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
return color;
else
return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method());
}
-
+
bool
SpiralGradient::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
class SpiralGradient : public synfig::Layer_Composite, public synfig::Layer_NoDeform
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
synfig::Gradient gradient;
float calc_supersample(const synfig::Point &x, float pw,float ph)const;
public:
-
+
SpiralGradient();
-
+
virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String & param)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
-
+
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
-
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+
virtual Vocab get_param_vocab()const;
}; // END of class SpiralGradient
return false;
}
string temp_file="/tmp/deleteme.png";
-
+
if(filename.find("psd")!=String::npos)
command=strprintf("convert \"%s\" -flatten \"png32:%s\"\n",filename.c_str(),temp_file.c_str());
else
command=strprintf("convert \"%s\" \"png32:%s\"\n",filename.c_str(),temp_file.c_str());
-
+
synfig::info("command=%s",command.c_str());
-
+
if(system(command.c_str())!=0)
return false;
Importer::Handle importer(Importer::open(temp_file));
-
+
DEBUGPOINT();
if(!importer)
else synfig::error(_("Unable to open ")+temp_file);
return false;
}
-
+
DEBUGPOINT();
if(!importer->get_frame(surface,0,cb))
else synfig::error(_("Unable to get frame from ")+temp_file);
return false;
}
-
+
if(!surface)
{
if(cb)cb->error(_("Bad surface from ")+temp_file);
else synfig::error(_("Bad surface from ")+temp_file);
- return false;
+ return false;
}
if(1)
Surface bleh(surface);
surface=bleh;
-
+
//remove(temp_file.c_str());
DEBUGPOINT();
return true;
-
+
#else
if(file)
pclose(file);
return true;
#endif
-
-
+
+
}
FILE *file;
int cur_frame;
synfig::Surface frame;
-
+
public:
imagemagick_mptr(const char *filename);
return false;
}
- //etl::yield();
+ //etl::yield();
return true;
}
if(!fwrite(buffer,channels(pf),desc.get_w(),file))
return false;
-
+
return true;
}
virtual bool set_rend_desc(synfig::RendDesc *desc);
virtual bool init();
virtual bool start_frame(synfig::ProgressCallback *cb);
- virtual void end_frame();
+ virtual void end_frame();
virtual synfig::Color * start_scanline(int scanline);
virtual bool end_scanline();
};
{
struct my_error_mgr jerr;
filename=file_name;
-
+
/* Open the file pointer */
FILE *file = fopen(file_name, "rb");
if (!file)
throw String("error on importer construction, *WRITEME*1");
return;
}
-
+
/* Step 1: allocate and initialize JPEG decompression object */
-
+
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
-
+
/* Step 2: specify data source (eg, a file) */
-
+
jpeg_stdio_src(&cinfo, file);
-
+
/* Step 3: read file parameters with jpeg_read_header() */
-
+
(void) jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.doc for more info.
*/
-
+
/* Step 4: set parameters for decompression */
-
+
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
-
+
/* Step 5: Start decompressor */
-
+
(void) jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
synfig::error("jpeg_mptr: error: alloc of \"buffer\" failed (bug?)");
throw String("alloc of \"buffer\" failed (bug?)");
}
-
+
int x;
int y;
surface_buffer.set_wh(cinfo.output_width,cinfo.output_height);
for(y=0;y<surface_buffer.get_h();y++)
{
int x;
- jpeg_read_scanlines(&cinfo, buffer, 1);
+ jpeg_read_scanlines(&cinfo, buffer, 1);
for(x=0;x<surface_buffer.get_w();x++)
{
float r=gamma().g_U8_to_F32((unsigned char)buffer[0][x*3+0]);
}
}
break;
-
+
case 1:
for(y=0;y<surface_buffer.get_h();y++)
{
- jpeg_read_scanlines(&cinfo, buffer, 1);
+ jpeg_read_scanlines(&cinfo, buffer, 1);
for(x=0;x<surface_buffer.get_w();x++)
{
float gray=gamma().g_U8_to_F32((unsigned char)buffer[0][x]);
throw String("error on importer construction, *WRITEME*6");
return;
}
-
+
/* Step 7: Finish decompression */
-
+
(void) jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
-
+
/* Step 8: Release JPEG decompression object */
-
+
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
-
+
/* After finish_decompress, we can close the input file.
* Here we postpone it until after no more JPEG errors are possible,
* so as to simplify the setjmp error logic above. (Actually, I don't
buffer=NULL;
ready=false;
quality=95;
- color_buffer=0;
+ color_buffer=0;
set_remove_alpha();
}
jpeg_trgt::start_frame(synfig::ProgressCallback *callback)
{
int w=desc.get_w(),h=desc.get_h();
-
+
if(file && file!=stdout)
fclose(file);
if(filename=="-")
newfilename(filename),
ext(find(filename.begin(),filename.end(),'.'),filename.end());
newfilename.erase(find(newfilename.begin(),newfilename.end(),'.'),newfilename.end());
-
+
newfilename+=etl::strprintf("%04d",imagecount)+ext;
file=fopen(newfilename.c_str(),"wb");
if(callback)callback->task(newfilename);
file=fopen(filename.c_str(),"wb");
if(callback)callback->task(filename);
}
-
+
if(!file)
return false;
-
+
delete [] buffer;
buffer=new unsigned char[3*w];
-
+
delete [] color_buffer;
color_buffer=new Color[w];
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
-
+
/* Step 4: Start compressor */
-
+
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
-
+
ready=true;
return true;
}
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
-
+
bool multi_image,ready;
int imagecount;
synfig::String filename;
#include <synfig/layer.h>
//#include "mptr.h"
-#include "trgt_av.h"
+#include "trgt_av.h"
#endif
{
int w,h;
int fps;
-
- int bitrate;
+
+ int bitrate;
};
struct AudioInfo
AVFrame *picture;
uint8_t *picture_buf;
int size;
-
+
picture = avcodec_alloc_frame();
if (!picture)
return NULL;
av_free(picture);
return NULL;
}
- avpicture_fill((AVPicture *)picture, picture_buf,
+ avpicture_fill((AVPicture *)picture, picture_buf,
pix_fmt, width, height);
return picture;
}
Surface::const_pen p = s.begin();
unsigned int w,h;
Color c;
-
+
uint8_t *ptr;
int stride;
-
+
w = s.size().x;
h = s.size().y;
-
+
ptr = pic->data[0];
stride = pic->linesize[0];
for(j = 0; j < h; j++, p.inc_y(), ptr += stride)
{
uint8_t *tptr = ptr;
-
+
//use convert_color_format instead...
#if 0
const int channels = 3;
-
+
for(int i = 0; i < w; i++, p.inc_x(), tptr += channels)
{
c = p.get_value();
-
+
Color::value_type r = c.get_r();
Color::value_type g = c.get_g();
Color::value_type b = c.get_b();
Color::value_type a = c.get_a();
-
+
//premultiply alpha
r *= a;
g *= a;
b *= a;
-
+
//essentially treats it as if it has a background color of black
-
+
//we must also clamp the rgb values [0,1]
r = min(1.0f,r);
g = min(1.0f,g);
b = min(1.0f,b);
-
+
r = max(0.0f,r);
g = max(0.0f,g);
b = max(0.0f,b);
tptr[1] = (int)(g*255);
tptr[2] = (int)(b*255);
}
-
+
p.dec_x(w);
#else
-
+
convert_color_format((unsigned char *)tptr,&p.get_value(),w,PF_RGB,gamma);
-
+
#endif
}
}
void *samples;
vector<unsigned char>audiobuffer;
-
+
int audio_input_frame_size;
-
+
bool open(AVFormatContext *formatc, AVStream *stream)
{
AVCodecContext *context;
AVCodec *codec;
-
+
context = &stream->codec;
-
+
//find audio encoder
codec = avcodec_find_encoder(context->codec_id);
if(!codec)
synfig::warning("audio-open: could not find codec");
return 0;
}
-
+
//open the codec
if(avcodec_open(context, codec) < 0)
{
synfig::warning("audio-open: could not open codec");
return 0;
}
-
+
/* hardcoded example for generating samples array*/
/*
t = 0;
tincr = 2 * M_PI * 110.0 / c->sample_rate;
tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;*/
-
+
audiobuffer.resize(10000);
-
+
/* ugly hack for PCM codecs (will be removed ASAP with new PCM
support to compute the input frame size in samples */
if (context->frame_size <= 1) {
} else {
audio_input_frame_size = context->frame_size;
}
-
+
//hardcoded array
//samples = (int16_t *)malloc(audio_input_frame_size * 2 * c->channels);
-
+
return true;
}
-
+
bool write_frame(AVFormatContext *formatc, AVStream *stream, void *samples)
{
int size;
AVCodecContext *context;
-
+
context = &stream->codec;
-
+
//hardcoded in example
//must read in from somewhere...
//get_audio_frame(samples, audio_input_frame_size, c->channels);
-
+
//encode the audio
const short int*samps=(const short int *)samples; //assuming it's set from somewhere right now
-
+
size = avcodec_encode_audio(context, &audiobuffer[0], audiobuffer.size(), samps);
-
+
//write the compressed audio to a file
if(av_write_frame(formatc, stream->index, &audiobuffer[0], size) != 0)
{
synfig::warning("audio-write_frame: unable to write the entire audio frame");
return 0;
}
-
+
return true;
}
-
+
void close(AVFormatContext *formatc, AVStream *stream)
{
//we may also want to catch delayed frames from here (don't for now)
-
+
if(stream)
{
avcodec_close(&stream->codec);
}
-
+
//if(samples)av_free(samples);
audiobuffer.resize(0);
}
{
public:
AVFrame *encodable; //for compressiong and output to a file (in compatible pixel format)
-
+
vector<unsigned char> videobuffer;
-
+
bool startedencoding;
-
+
//int stream_nb_frames;
-
+
bool open(AVFormatContext *formatc, AVStream *stream)
{
if(!formatc || !stream)
synfig::warning("Attempt to open a video codec with a bad format or stream");
return false;
}
-
+
//codec and context
AVCodec *codec;
AVCodecContext *context;
-
+
//get from inside stream
context = stream->codec;
-
+
//search for desired codec (contained in the stream)
codec = avcodec_find_encoder(context->codec_id);
if(!codec)
synfig::warning("Open_video: could not find desired codec");
return 0;
}
-
+
//try to open the codec
- if(avcodec_open(context, codec) < 0)
+ if(avcodec_open(context, codec) < 0)
{
synfig::warning("open_video: could not open desired codec");
return 0;
}
-
- videobuffer.resize(0);
+
+ videobuffer.resize(0);
if(!(formatc->oformat->flags & AVFMT_RAWPICTURE))
{
//resize buffer to desired buffersize
videobuffer.resize(200000); //TODO: need to figure out a good size
}
-
+
//allocate the base picture which will be used to encode
/*picture = alloc_picture(PIX_FMT_RGBA32, context->width, context->height);
if(!picture)
synfig::warning("open_video: could not allocate the picture to be encoded");
return 0;
}*/
-
+
//if our output (rgb) needs to be translated to a different coordinate system, need a temporary picture in that color space
-
+
/* Should use defaults of RGB
Possible formats:
PIX_FMT_RGB24
PIX_FMT_BGR24
PIX_FMT_RGBA32 //stored in cpu endianness (!!!!)
-
+
(possibly translate directly to required coordinate systems later on... less error)
*/
encodable = NULL;
if(context->pix_fmt != PIX_FMT_RGB24)
{
encodable = alloc_picture(context->pix_fmt, context->width, context->height);
- if(!encodable)
+ if(!encodable)
{
synfig::warning("open_video: could not allocate encodable picture");
return 0;
}
}
-
+
return true;
}
-
+
//write a frame with the frame passed in
bool write_frame(AVFormatContext *formatc, AVStream *stream, AVFrame *pict)
{
synfig::warning("Attempt to open a video codec with a bad format or stream");
return false;
}
-
- int size,
+
+ int size,
ret = 0;
AVCodecContext *context = stream->codec;
-
+
/*
If pict is invalid (NULL), then we are done compressing frames and we are trying to get
- the buffer cleared out (or if it's already in the right format) so no transofrm necessary
+ the buffer cleared out (or if it's already in the right format) so no transofrm necessary
*/
if ( pict )
{
startedencoding = true;
}
-
-
+
+
if ( pict && context->pix_fmt != PIX_FMT_RGB24 )
{
//We're using RGBA at the moment, write custom conversion code later (get less accuracy errors)
- img_convert((AVPicture *)encodable, context->pix_fmt,
+ img_convert((AVPicture *)encodable, context->pix_fmt,
(AVPicture *)pict, PIX_FMT_RGB24,
context->width, context->height);
-
+
pict = encodable;
}
-
+
AVPacket pkt;
av_init_packet(&pkt);
pkt.stream_index = stream->index;
pkt.pts = context->coded_frame->pts;
if( context->coded_frame && context->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;
-
+
//cludge for raw picture format (they said they'd fix)
if (formatc->oformat->flags & AVFMT_RAWPICTURE)
{
ret = av_write_frame(formatc, &pkt);
}
- else
+ else
{
//encode our given image
size = avcodec_encode_video(context, &videobuffer[0], videobuffer.size(), pict);
-
+
//if greater than zero we've got stuff to write
if (size > 0)
{
pkt.flags |= PKT_FLAG_KEY;
ret = av_write_frame(formatc, &pkt);
-
+
//error detect - possibly throw later...
if(ret < 0)
{
synfig::warning("write_frame: error while writing video frame");
- return false;
+ return false;
}
}
//if 0, it was buffered (if invalid picture we don't have ANY data left)
return false;
startedencoding = false;
}
-
+
//buffered picture
}
}
-
+
return true;
}
-
+
void close(AVFormatContext *formatc, AVStream *stream)
{
if(stream)
avcodec_close(stream->codec);
-
- if (encodable)
+
+ if (encodable)
{
free_picture(encodable);
encodable = 0;
}
-
+
videobuffer.resize(0);
}
};
class Target_LibAVCodec::LibAVEncoder
{
public:
-
+
bool initialized;
-
+
AVOutputFormat *format; //reference to global, do not delete
AVFormatContext *formatc;
-
+
AVStream *video_st;
//AVStream *audio_st;
-
+
double video_pts;
//double audio_pts;
VideoEncoder vid;
VideoInfo vInfo;
-
+
/*AudioEncoder aud;
AudioInfo aInfo;*/
{
format = 0;
formatc = 0;
-
+
//video settings
video_st = 0;
video_pts = 0;
-
+
vid.encodable = 0;
//vid.stream_nb_frames = 2; //reasonable default
-
+
initialized = false;
picture = 0;
frame_count = 0;
- num_frames = 0;
-
- //aud.samples = 0;
+ num_frames = 0;
+
+ //aud.samples = 0;
//audio_st = 0;
//audio_pts = 0;
}
{
CleanUp();
}
-
+
bool Initialize(const char *filename, const char *typestring)
{
//guess if we have a type string, otherwise use filename
{
format = guess_format(NULL, filename, NULL);
}
-
+
if(!format)
{
synfig::warning("Unable to Guess the output, defaulting to mpeg");
format = guess_format("mpeg", NULL, NULL);
}
-
- if(!format)
+
+ if(!format)
{
synfig::warning("Unable to find output format");
return 0;
}
-
+
//allocate the output context
formatc = (AVFormatContext *)av_mallocz(sizeof(AVFormatContext));
if(!formatc)
}
//set the output format to the one we found
formatc->oformat = format;
-
+
//print the output filename
snprintf(formatc->filename, sizeof(formatc->filename), "%s", filename);
-
+
//initial
video_st = NULL;
//audio_st = NULL;
-
+
//video stream
- if(format->video_codec != CODEC_ID_NONE)
+ if(format->video_codec != CODEC_ID_NONE)
{
video_st = add_video_stream(format->video_codec,vInfo);
if(!video_st)
av_free(formatc);
}
}
-
+
//audio stream
/*if(format->audio_codec != CODEC_ID_NONE)
{
audio_st = add_audio_stream(format->audio_codec,aInfo);
}*/
-
+
//set output parameters: required in ALL cases
-
+
video_st->codec->time_base= (AVRational){1,vInfo.fps};
video_st->codec->width = vInfo.w;
video_st->codec->height = vInfo.h;
video_st->codec->pix_fmt = PIX_FMT_YUV420P;
-
+
//dump the formatting information as the file header
dump_format(formatc, 0, filename, 1);
-
+
//open codecs and allocate buffers
if(video_st)
{
{
synfig::warning("Could not open audio encoder");
return 0;
- }
+ }
}*/
-
+
//open output file
if(!(format->flags & AVFMT_NOFILE))
{
return 0;
}
}
-
+
//allocate the picture to render to
//may have to retrieve the width, height from the codec... for resizing...
picture = alloc_picture(PIX_FMT_RGB24,vInfo.w,vInfo.h);//video_st->codec.width, video_st->codec.height);
synfig::warning("Unable to allocate the temporary AVFrame surface");
return 0;
}
-
+
initialized = true;
//vInfo.w = video_st->codec.width;
//vInfo.h = video_st->codec.height;
-
+
//write the stream header
av_write_header(formatc);
-
+
return true;
}
-
+
void CleanUp()
{
int i;
-
+
if(picture) free_picture(picture);
-
+
//do all the clean up file rendering
if(formatc && video_st)
{
- //want to scan in delayed frames until no longer needed (TODO)
+ //want to scan in delayed frames until no longer needed (TODO)
if(vid.startedencoding) while( vid.write_frame(formatc, video_st, 0) );
-
+
//may want to move this... probably to the end of the last frame...
av_write_trailer(formatc);
}
-
+
//close codecs
if (video_st)
vid.close(formatc,video_st);
/*if (audio_st)
aud.close(formatc,audio_st);*/
-
+
/* write the trailer, if any */
if(formatc)
{
{
av_freep(&formatc->streams[i]);
}
-
+
if(!(format->flags & AVFMT_NOFILE))
{
/* close the output file */
url_fclose(&formatc->pb);
}
-
+
/* free the stream */
av_free(formatc);
}
-
+
initialized = false;
-
+
format = 0;
formatc = 0;
-
+
//video settings
video_st = 0;
video_pts = 0;
-
+
vid.encodable = 0;
//vid.stream_nb_frames = 2; //reasonable default
-
+
initialized = false;
- picture = 0;
+ picture = 0;
}
//create a video output stream
{
AVCodecContext *context;
AVStream *st;
-
+
st = av_new_stream(formatc, 0);
if(!st)
{
synfig::warning("video-add_stream: Unable to allocate stream");
return 0;
}
-
+
context = st->codec;
context->codec_id = (CodecID)codec_id;
context->codec_type = CODEC_TYPE_VIDEO;
-
+
//PARAMETERS MUST BE PASSED IN SOMEHOW (ANOTHER FUNCTION PARAMETER???)
-
+
/* resolution must be a multiple of two */
context->width = info.w;
context->height = info.h;
-
+
//have another way to input these
context->bit_rate = info.bitrate; //TODO: Make dependant on the quality
-
+
/* frames per second */
// FIXME: Port next two lines to recent libavcodec versions
//context->frame_rate = info.fps;
//context->frame_rate_base = 1;
-
+
/* "High Quality" */
context->mb_decision=FF_MB_DECISION_BITS;
-
+
context->gop_size = info.fps/4; /* emit one intra frame every twelve frames at most */
-
+
//HACK: MPEG requires b frames be set... any better way to do this?
if (context->codec_id == CODEC_ID_MPEG1VIDEO ||
context->codec_id == CODEC_ID_MPEG2VIDEO)
/* just for testing, we also add B frames */
context->max_b_frames = 2;
}
-
+
return st;
}
-
+
// add an audio output stream
AVStream *add_audio_stream(int codec_id,const AudioInfo &aInfo)
{
AVCodecContext *context;
AVStream *stream;
-
+
stream = av_new_stream(formatc, 1);
if(!stream)
{
synfig::warning("could not alloc stream");
return 0;
}
-
+
context = stream->codec;
- context->codec_id = (CodecID)codec_id;
+ context->codec_id = (CodecID)codec_id;
context->codec_type = CODEC_TYPE_AUDIO;
-
+
/* put sample parameters */
context->bit_rate = 64000;
context->sample_rate = 44100;
context->channels = 2;
-
+
return stream;
}
};
av_register_all();
}
set_remove_alpha();
-
+
data = new LibAVEncoder;
}
// to be rendered! given_desc is the suggestion, and
// you need to modify it to suit the needs of the codec.
// ie: Making the pixel dimensions divisible by 8, etc...
-
+
desc=*given_desc;
-
+
//resize surface (round even)
int w = desc.get_w();
int h = desc.get_h();
Point br = desc.get_br();
Real pw = desc.get_pw();
Real ph = desc.get_ph();
-
+
//resize to the size it should be...
//desc.set_subwindow(-offx/2,-offy/2, desc.get_w() - offx?(offx + 8):0, desc.get_h() - offy?(offy + 8):0);
- //if resolution is broken, change the size... or something
+ //if resolution is broken, change the size... or something
//budge to nearest pixel values
if(w&1)
{
w += 1;
tl[0] -= pw/2;
- br[0] += pw/2;
+ br[0] += pw/2;
}
-
+
if(h&1)
{
h += 1;
tl[1] -= ph/2;
br[1] += ph/2;
}
-
+
desc.set_w(w);
desc.set_h(h);
desc.set_tl(tl);
desc.set_br(br);
-
+
data->vInfo.w = w;
data->vInfo.h = h;
-
+
//may want to round frame rate
data->vInfo.fps = (int)floor(desc.get_frame_rate()+0.5);
#define MEGABYTES_PER_HOUR(x) (((x)*1024/3600*1024*8)/*/640*w/480*h*/)
data->vInfo.bitrate = MEGABYTES_PER_HOUR(400);
//data->vInfo.bitrate = 800000; //make customizable somehow
-
+
desc.set_frame_rate(data->vInfo.fps);
-
+
data->frame_count = desc.get_frame_start();
data->num_frames = desc.get_frame_end()+1; //number of frames should be 1 greater than the last one
-
+
surface.set_wh(data->vInfo.w,data->vInfo.h);
-
+
return true;
}
{
//AVStream *audio_st = data->audio_st;
AVStream *video_st = data->video_st;
-
+
AVFormatContext *formatc = data->formatc;
-
+
//double &audio_pts = data->audio_pts;
//double &video_pts = data->video_pts;
-
- //ignore audio for now
+
+ //ignore audio for now
/*if (audio_st)
audio_pts = (double)audio_st->pts.val * formatc->pts_num / formatc->pts_den;
else
audio_pts = 0.0;
-
+
if (video_st)
video_pts = (double)video_st->pts.val * formatc->pts_num / formatc->pts_den;
else
video_pts = 0.0;*/
//hardcoded crappiness
- /*if ((!audio_st || audio_pts >= STREAM_DURATION) &&
+ /*if ((!audio_st || audio_pts >= STREAM_DURATION) &&
(!video_st || video_pts >= STREAM_DURATION))
break;*/
-
+
if(data->frame_count >= data->num_frames) return;
-
+
//copy the current surface to the buffer
if(data->picture)convert_surface_frame(data->picture,surface,gamma());
-
+
//encode the frame and write it to the file
if(!data->vid.write_frame(formatc,video_st,data->picture))
{
synfig::warning("Unable to write a frame");
}
-
+
data->frame_count++;
if(data->frame_count >= data->num_frames)
{
data->CleanUp();
}
-
+
/* write interleaved audio and video frames */
/*if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
data->aud.write_frame(formatc,audio_st);
bool
Target_LibAVCodec::start_frame(synfig::ProgressCallback *callback)
-{
+{
//prepare all the color buffer stuff, etc.
-
+
return true;
}
Target_LibAVCodec::start_scanline(int scanline)
{
return surface[scanline];
-
+
return 0; // This should kill the render process
}
synfig::warning("Unable to Initialize the audio video encoders");
return 0;
}
-
+
return true;
}
class LibAVEncoder;
LibAVEncoder *data;
-
+
static bool registered;
-
+
synfig::Surface surface;
public:
NoiseDistort::color_func(const Point &point, float supersample,Context context)const
{
Color ret(0,0,0,0);
-
+
float x(point[0]/size[0]*(1<<detail));
float y(point[1]/size[1]*(1<<detail));
-
+
int i;
Time time;
time=speed*curr_time;
int smooth((!speed && smooth==3)?5:smooth);
-
+
{
Vector vect(0,0);
for(i=0;i<detail;i++)
if(vect[0]<-1)vect[0]=-1;if(vect[0]>1)vect[0]=1;
if(vect[1]<-1)vect[1]=-1;if(vect[1]>1)vect[1]=1;
-
+
if(turbulent)
{
vect[0]=abs(vect[0]);
vect[1]=abs(vect[1]);
}
-
+
x/=2.0f;
y/=2.0f;
}
}
vect[0]=(vect[0]-0.5f)*displacement[0];
vect[1]=(vect[1]-0.5f)*displacement[1];
-
+
ret=context.get_color(point+vect);
}
return ret;
IMPORT(detail);
IMPORT(turbulent);
IMPORT(displacement);
- return Layer_Composite::set_param(param,value);
+ return Layer_Composite::set_param(param,value);
}
ValueBase
EXPORT(detail);
EXPORT(displacement);
EXPORT(turbulent);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
NoiseDistort::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("displacement")
.set_local_name(_("Displacement"))
);
ret.push_back(ParamDesc("turbulent")
.set_local_name(_("Turbulent"))
);
-
+
return ret;
}
if(Color::is_onto(get_blend_method()))
return context.get_full_bounding_rect();
-
+
Rect bounds(context.get_full_bounding_rect().expand_x(displacement[0]).expand_y(displacement[1]));
-
+
return bounds;
}
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
public:
NoiseDistort();
-
+
virtual bool set_param(const synfig::String ¶m, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String ¶m)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
//virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual void set_time(synfig::Context context, synfig::Time time)const;
virtual void set_time(synfig::Context context, synfig::Time time, const synfig::Point &point)const;
virtual synfig::Rect get_bounding_rect(synfig::Context context)const;
Noise::color_func(const Point &point, float pixel_size,Context context)const
{
Color ret(0,0,0,0);
-
+
float x(point[0]/size[0]*(1<<detail));
float y(point[1]/size[1]*(1<<detail));
float x2(0),y2(0);
-
+
if(super_sample&&pixel_size)
{
x2=(point[0]+pixel_size)/size[0]*(1<<detail);
y2=(point[1]+pixel_size)/size[1]*(1<<detail);
}
-
+
int i;
Time time;
time=speed*curr_time;
int smooth((!speed && Noise::smooth==3)?5:Noise::smooth);
-
+
float t(time);
{
{
amount=random(smooth,0+(detail-i)*5,x,y,t)+amount*0.5;
if(amount<-1)amount=-1;if(amount>1)amount=1;
-
+
if(super_sample&&pixel_size)
{
amount2=random(smooth,0+(detail-i)*5,x2,y,t)+amount2*0.5;
x2*=0.5f;
y2*=0.5f;
}
-
+
if(do_alpha)
{
alpha=random(smooth,3+(detail-i)*5,x,y,t)+alpha*0.5;
if(alpha<-1)alpha=-1;if(alpha>1)alpha=1;
}
-
+
if(turbulent)
{
amount=abs(amount);
alpha=abs(alpha);
}
-
+
x*=0.5f;
y*=0.5f;
//t*=0.5f;
amount3=amount3/2.0f+0.5f;
}
}
-
+
if(super_sample && pixel_size)
ret=gradient(amount,max(amount3,max(amount,amount2))-min(amount3,min(amount,amount2)));
else
IMPORT(gradient);
IMPORT(turbulent);
IMPORT(super_sample);
-
- return Layer_Composite::set_param(param,value);
+
+ return Layer_Composite::set_param(param,value);
}
ValueBase
EXPORT(detail);
EXPORT(do_alpha);
EXPORT(gradient);
- EXPORT(turbulent)
+ EXPORT(turbulent)
EXPORT(super_sample);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
Noise::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("gradient")
.set_local_name(_("Gradient"))
);
ret.push_back(ParamDesc("super_sample")
.set_local_name(_("Super Sampling"))
);
-
+
return ret;
}
return true;
}
-
+
int x,y;
Surface::pen pen(surface->begin());
float supersampleradius((abs(pw)+abs(ph))*0.5f);
if(quality>=8)
supersampleradius=0;
-
+
if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
bool turbulent;
bool do_displacement;
synfig::Vector displacement;
-
+
//void sync();
mutable synfig::Time curr_time;
-
+
bool super_sample;
synfig::Color color_func(const synfig::Point &x, float supersample,synfig::Context context)const;
public:
Noise();
-
+
virtual bool set_param(const synfig::String ¶m, const synfig::ValueBase &value);
virtual synfig::ValueBase get_param(const synfig::String ¶m)const;
virtual synfig::Color get_color(synfig::Context context, const synfig::Point &pos)const;
virtual bool accelerated_render(synfig::Context context,synfig::Surface *surface,int quality, const synfig::RendDesc &renddesc, synfig::ProgressCallback *cb)const;
- synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
+ synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
virtual void set_time(synfig::Context context, synfig::Time time)const;
virtual void set_time(synfig::Context context, synfig::Time time, const synfig::Point &point)const;
{
next=x;
}
-
+
unsigned long i32()
{
static const unsigned long a(1664525);
static const unsigned long c(1013904223);
-
+
return next=next*a+c;
}
float f()
{
static const float m(int(65535));
-
+
return float(i16())/m;
}
};
{
seed_=x;
}
-
+
float
Random::operator()(const int salt,const int x,const int y,const int t)const
{
static const unsigned int b(11213);
static const unsigned int c(36979);
static const unsigned int d(31337);
-
+
quick_rng rng(
( static_cast<unsigned int>(x+y) * a ) ^
( static_cast<unsigned int>(y+t) * b ) ^
( static_cast<unsigned int>(t+x) * c ) ^
- ( static_cast<unsigned int>(seed_+salt) * d )
+ ( static_cast<unsigned int>(seed_+salt) * d )
);
-
+
return rng.f() * 2.0f - 1.0f;
}
//Using catmull rom interpolation because it doesn't blur at all
//bezier curve with intermediate ctrl pts: 0.5/3(p(i+1) - p(i-1)) and similar
float xfa [4], tfa[4];
-
+
//precalculate indices (all clamped) and offset
const int xa[] = {x-1,x,x+1,x+2};
-
+
const int ya[] = {y-1,y,y+1,y+2};
const int ta[] = {t-1,t,t+1,t+2};
-
+
const float dx(xf-x);
const float dy(yf-y);
const float dt(tf-t);
-
+
//figure polynomials for each point
- const float txf[] =
+ const float txf[] =
{
0.5*dx*(dx*(dx*(-1) + 2) - 1), //-t + 2t^2 -t^3
0.5*(dx*(dx*(3*dx - 5)) + 2), //2 - 5t^2 + 3t^3
0.5*dx*(dx*(-3*dx + 4) + 1), //t + 4t^2 - 3t^3
0.5*dx*dx*(dx-1) //-t^2 + t^3
};
-
- const float tyf[] =
+
+ const float tyf[] =
{
0.5*dy*(dy*(dy*(-1) + 2) - 1), //-t + 2t^2 -t^3
0.5*(dy*(dy*(3*dy - 5)) + 2), //2 - 5t^2 + 3t^3
0.5*dy*dy*(dy-1) //-t^2 + t^3
};
- const float ttf[] =
+ const float ttf[] =
{
0.5*dt*(dt*(dt*(-1) + 2) - 1), //-t + 2t^2 -t^3
0.5*(dt*(dt*(3*dt - 5)) + 2), //2 - 5t^2 + 3t^3
0.5*dt*(dt*(-3*dt + 4) + 1), //t + 4t^2 - 3t^3
0.5*dt*dt*(dt-1) //-t^2 + t^3
};
-
- //evaluate polynomial for each row
+
+ //evaluate polynomial for each row
for(int i = 0; i < 4; ++i)
{
for(int j = 0; j < 4; ++j)
}
xfa[i] = tfa[0]*txf[0] + tfa[1]*txf[1] + tfa[2]*txf[2] + tfa[3]*txf[3];
}
-
+
//return the cumulative column evaluation
return xfa[0]*tyf[0] + xfa[1]*tyf[1] + xfa[2]*tyf[2] + xfa[3]*tyf[3];
#undef f
#define ZT(i,j,k) ret+=FT(i,j,k)
#define X(i,j) // placeholder... To make box more symetric
#define XT(i,j,k) // placeholder... To make box more symetric
-
+
float a(xf-x), b(yf-y);
-
+
// Interpolate
float ret(F(0,0));
Z(-1,-1); Z(-1, 0); Z(-1, 1); Z(-1, 2);
return ret;
}
-
+
case 3: // Spline (animated)
{
float a(xf-x), b(yf-y), c(tf-t);
-
+
// Interpolate
float ret(FT(0,0,0));
ZT(-1,-1,-1); ZT(-1, 0,-1); ZT(-1, 1,-1); ZT(-1, 2,-1);
ZT( 0,-1, 2); ZT( 0, 0, 2); ZT( 0, 1, 2); ZT( 0, 2, 2);
ZT( 1,-1, 2); ZT( 1, 0, 2); ZT( 1, 1, 2); ZT( 1, 2, 2);
ZT( 2,-1, 2); ZT( 2, 0, 2); ZT( 2, 1, 2); ZT( 2, 2, 2);
-
+
return ret;
/*
a=(1.0f-cos(a*3.1415927))*0.5f;
b=(1.0f-cos(b*3.1415927))*0.5f;
-
+
// We don't perform this on the time axis, otherwise we won't
// get smooth motion
//c=(1.0f-cos(c*3.1415927))*0.5f;
-
+
float d=1.0-a;
float e=1.0-b;
float f=1.0-c;
-
+
int x2=x+1,y2=y+1,t2=t+1;
-
+
return
(*this)(subseed,x,y,t)*(d*e*f)+
(*this)(subseed,x2,y,t)*(a*e*f)+
}
else
{
-
+
float a=xf-x;
float b=yf-y;
float c=tf-t;
-
+
float d=1.0-a;
float e=1.0-b;
float f=1.0-c;
-
+
int x2=x+1,y2=y+1,t2=t+1;
-
+
return
(*this)(subseed,x,y,t)*(d*e*f)+
(*this)(subseed,x2,y,t)*(a*e*f)+
{
int seed_;
public:
-
+
void set_seed(int x);
int get_seed()const { return seed_; }
-
- float operator()(int subseed,int x,int y=0, int t=0)const;
- float operator()(int smooth,int subseed,float x,float y=0, float t=0)const;
+
+ float operator()(int subseed,int x,int y=0, int t=0)const;
+ float operator()(int smooth,int subseed,float x,float y=0, float t=0)const;
};
/* === E N D =============================================================== */
in.setFrameBuffer (reinterpret_cast<Imf::Rgba *>(in_surface[0]), 1, w);
in.readPixels (in.dataWindow().min.y, in.dataWindow().max.y);
-
+
int x;
int y;
out_surface.set_wh(w,h);
return false;
}
- return true;
+ return true;
}
#ifndef USE_HALF_TYPE
buffer_color=0;
#endif
-
+
// OpenEXR uses linear gamma
gamma().set_gamma(1.0);
}
exr_trgt::start_frame(synfig::ProgressCallback *cb)
{
int w=desc.get_w(),h=desc.get_h();
-
+
String frame_name;
-
+
if(exr_file)
delete exr_file;
if(multi_image)
newfilename(filename),
ext(find(filename.begin(),filename.end(),'.'),filename.end());
newfilename.erase(find(newfilename.begin(),newfilename.end(),'.'),newfilename.end());
-
+
newfilename+=etl::strprintf("%04d",imagecount)+ext;
frame_name=newfilename;
if(cb)cb->task(newfilename);
//if(buffer) delete [] buffer;
//buffer=new Imf::Rgba[w];
out_surface.set_wh(w,h);
-
+
return true;
}
delete exr_file;
}
-
+
exr_file=0;
-
+
imagecount++;
}
bline.push_back(BLinePoint());
bline.push_back(BLinePoint());
bline.push_back(BLinePoint());
- bline[0].set_vertex(Point(0,1));
- bline[1].set_vertex(Point(0,-1));
+ bline[0].set_vertex(Point(0,1));
+ bline[1].set_vertex(Point(0,-1));
bline[2].set_vertex(Point(1,0));
- bline[0].set_tangent(bline[1].get_vertex()-bline[2].get_vertex()*0.5f);
- bline[1].set_tangent(bline[2].get_vertex()-bline[0].get_vertex()*0.5f);
- bline[2].set_tangent(bline[0].get_vertex()-bline[1].get_vertex()*0.5f);
- bline[0].set_width(1.0f);
- bline[1].set_width(1.0f);
- bline[2].set_width(1.0f);
+ bline[0].set_tangent(bline[1].get_vertex()-bline[2].get_vertex()*0.5f);
+ bline[1].set_tangent(bline[2].get_vertex()-bline[0].get_vertex()*0.5f);
+ bline[2].set_tangent(bline[0].get_vertex()-bline[1].get_vertex()*0.5f);
+ bline[0].set_width(1.0f);
+ bline[1].set_width(1.0f);
+ bline[2].set_width(1.0f);
bline_loop=true;
mass=(0.5);
splits=5;
));
bounding_rect.expand(position);
}
-
+
if(t>=1.0-stunt_growth)return;
synfig::Real sin_v=synfig::Angle::cos(split_angle).get();
synfig::Real cos_v=synfig::Angle::sin(split_angle).get();
-
+
synfig::Vector velocity1(vel[0]*sin_v-vel[1]*cos_v+random_factor*random(2,30+n+depth,t*splits,0.0f,0.0f),vel[0]*cos_v+vel[1]*sin_v+random_factor*random(2,32+n+depth,t*splits,0.0f,0.0f));
synfig::Vector velocity2(vel[0]*sin_v+vel[1]*cos_v+random_factor*random(2,31+n+depth,t*splits,0.0f,0.0f),-vel[0]*cos_v+vel[1]*sin_v+random_factor*random(2,33+n+depth,t*splits,0.0f,0.0f));
-
+
Plant::branch(n,depth+1,t,stunt_growth,position,velocity1);
Plant::branch(n,depth+1,t,stunt_growth,position,velocity2);
}
iter=--bline.end();
else
iter=next++;
-
+
for(;next!=bline.end();iter=next++)
{
bounding_rect.expand(iter->get_vertex());
Plant::sync()const
{
particle_list.clear();
-
+
bounding_rect=Rect::zero();
// Bline must have at least 2 points in it
if(bline.size()<=2)
return;
-
+
std::vector<synfig::BLinePoint>::const_iterator iter,next;
etl::hermite<Vector> curve;
-
+
Real step(abs(this->step));
-
+
int seg(0);
next=bline.begin();
-
+
if(bline_loop)
iter=--bline.end();
else
iter=next++;
-
+
for(;next!=bline.end();iter=next++,seg++)
{
curve.p1()=iter->get_vertex();
curve.t2()=next->get_tangent1();
curve.sync();
etl::derivative<etl::hermite<Vector> > deriv(curve);
-
+
Real f;
int i(0), b(round_to_int((1.0/step)/(float)sprouts-1));
if(b<=0)b=1;
for(f=0.0;f<1.0;f+=step,i++)
{
Point point(curve(f));
-
+
particle_list.push_back(Particle(
point,
gradient(0)
));
-
+
bounding_rect.expand(point);
-
+
Real stunt_growth(random(2,i,f+seg,0.0f,0.0f)/2.0+0.5);
stunt_growth*=stunt_growth;
-
+
Vector branch_velocity(deriv(f).norm()*velocity);
-
+
branch_velocity[0]+=random_factor*random(2,1,f*splits,0.0f,0.0f);
branch_velocity[1]+=random_factor*random(2,2,f*splits,0.0f,0.0f);
-
+
if(i%b==0)
branch(
i,
);
}
}
-
+
needs_sync_=false;
}
bline=value;
bline_loop=value.get_loop();
needs_sync_=true;
-
+
return true;
}
if(param=="seed" && value.same_as(int()))
IMPORT_PLUS(drag,needs_sync_=true);
IMPORT(size);
IMPORT(size_as_alpha);
-
+
return Layer_Composite::set_param(param,value);
}
/*
EXPORT(size);
EXPORT(size_as_alpha);
-
+
EXPORT_NAME();
EXPORT_VERSION();
bool
Plant::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
-{
+{
bool ret(context.accelerated_render(surface,quality,renddesc,cb));
if(is_disabled() || !ret)
return ret;
-
+
Surface dest_surface;
dest_surface.set_wh(surface->get_w(),surface->get_h());
dest_surface.clear();
-
+
const Point tl(renddesc.get_tl());
const Point br(renddesc.get_br());
radius*=color.get_a();
color.set_a(1);
}
-
+
x1=ceil_to_int((iter->point[0]-tl[0])/pw-(radius*0.5));
y1=ceil_to_int((iter->point[1]-tl[1])/ph-(radius*0.5));
x2=x1+round_to_int(radius);
y2=y1+round_to_int(radius);
-
+
if(x1>=surface->get_w() || y1>=surface->get_h())
continue;
x2=surface->get_w();
if(y2>=surface->get_h())
y2=surface->get_h();
-
+
if(x1<0)
x1=0;
if(y1<0)
y1=0;
-
+
int w(min(round_to_int(radius),x2-x1));
int h(min(round_to_int(radius),y2-y1));
-
+
if(w<=0 || h<=0)
continue;
-
+
Surface::alpha_pen surface_pen(dest_surface.get_pen(x1,y1),1.0f);
-
+
dest_surface.fill(color,surface_pen,w,h);
}
}
x=floor_to_int((iter->point[0]-tl[0])/pw-0.5f);
y=floor_to_int((iter->point[1]-tl[1])/ph-0.5f);
-
+
if(x>=surface->get_w()-1 || y>=surface->get_h()-1 || x<0 || y<0)
{
continue;
}
-
+
a=((iter->point[0]-tl[0])/pw-0.5f-x)*radius;
b=((iter->point[1]-tl[1])/ph-0.5f-y)*radius;
c=radius-a;
d=radius-b;
-
+
Surface::alpha_pen surface_pen(dest_surface.get_pen(x,y),1.0f);
-
+
surface_pen.set_alpha(c*d);
surface_pen.put_value(color);
surface_pen.inc_x();
surface_pen.put_value(color);
surface_pen.dec_x();
surface_pen.set_alpha(c*b);
- surface_pen.put_value(color);
+ surface_pen.put_value(color);
}
}
-
+
Surface::alpha_pen pen(surface->get_pen(0,0),get_amount(),get_blend_method());
dest_surface.blit_to(pen);
-
+
return true;
}
{
if(needs_sync_==true)
sync();
-
+
if(is_disabled())
return Rect::zero();
-
+
if(Color::is_onto(get_blend_method()))
return context.get_full_bounding_rect() & bounding_rect;
{
synfig::Point point;
synfig::Color color;
-
+
Particle(const synfig::Point &point,const synfig::Color& color):
point(point),color(color) { }
};
int sprouts;
synfig::Real random_factor;
Random random;
-
+
bool size_as_alpha;
mutable bool needs_sync_;
-
+
void branch(int n, int depth,float t, float stunt_growth, synfig::Point position,synfig::Vector velocity)const;
y_mask=rand()+rand()*RAND_MAX;
t_mask=rand()+rand()*RAND_MAX;
}
-
+
float
Random::operator()(const int salt,const int x,const int y,const int t)const
{
const int salt_hash(pool_[salt&(POOL_SIZE-1)]);
-
+
int index(((x^x_mask)+(y^y_mask)*234672+(t^t_mask)*8439573)^salt_hash);
-
+
index+=index*(index/POOL_SIZE);
-
+
return (float(pool_[index&(POOL_SIZE-1)])/float(RAND_MAX))*2.0f-1.0f;
}
//Using catmull rom interpolation because it doesn't blur at all
//bezier curve with intermediate ctrl pts: 0.5/3(p(i+1) - p(i-1)) and similar
float xfa [4], tfa[4];
-
+
//precalculate indices (all clamped) and offset
const int xa[] = {x-1,x,x+1,x+2};
-
+
const int ya[] = {y-1,y,y+1,y+2};
const int ta[] = {t-1,t,t+1,t+2};
-
+
const float dx(xf-x);
const float dy(yf-y);
const float dt(tf-t);
-
+
//figure polynomials for each point
- const float txf[] =
+ const float txf[] =
{
0.5*dx*(dx*(dx*(-1) + 2) - 1), //-t + 2t^2 -t^3
0.5*(dx*(dx*(3*dx - 5)) + 2), //2 - 5t^2 + 3t^3
0.5*dx*(dx*(-3*dx + 4) + 1), //t + 4t^2 - 3t^3
0.5*dx*dx*(dx-1) //-t^2 + t^3
};
-
- const float tyf[] =
+
+ const float tyf[] =
{
0.5*dy*(dy*(dy*(-1) + 2) - 1), //-t + 2t^2 -t^3
0.5*(dy*(dy*(3*dy - 5)) + 2), //2 - 5t^2 + 3t^3
0.5*dy*dy*(dy-1) //-t^2 + t^3
};
- const float ttf[] =
+ const float ttf[] =
{
0.5*dt*(dt*(dt*(-1) + 2) - 1), //-t + 2t^2 -t^3
0.5*(dt*(dt*(3*dt - 5)) + 2), //2 - 5t^2 + 3t^3
0.5*dt*(dt*(-3*dt + 4) + 1), //t + 4t^2 - 3t^3
0.5*dt*dt*(dt-1) //-t^2 + t^3
};
-
- //evaluate polynomial for each row
+
+ //evaluate polynomial for each row
for(int i = 0; i < 4; ++i)
{
for(int j = 0; j < 4; ++j)
}
xfa[i] = tfa[0]*txf[0] + tfa[1]*txf[1] + tfa[2]*txf[2] + tfa[3]*txf[3];
}
-
+
//return the cumulative column evaluation
return xfa[0]*tyf[0] + xfa[1]*tyf[1] + xfa[2]*tyf[2] + xfa[3]*tyf[3];
#undef f
#define ZT(i,j,k) ret+=FT(i,j,k)
#define X(i,j) // placeholder... To make box more symetric
#define XT(i,j,k) // placeholder... To make box more symetric
-
+
float a(xf-x), b(yf-y);
-
+
// Interpolate
float ret(F(0,0));
Z(-1,-1); Z(-1, 0); Z(-1, 1); Z(-1, 2);
return ret;
}
-
+
case 3: // Spline (animated)
{
float a(xf-x), b(yf-y), c(tf-t);
-
+
// Interpolate
float ret(FT(0,0,0));
ZT(-1,-1,-1); ZT(-1, 0,-1); ZT(-1, 1,-1); ZT(-1, 2,-1);
ZT( 0,-1, 2); ZT( 0, 0, 2); ZT( 0, 1, 2); ZT( 0, 2, 2);
ZT( 1,-1, 2); ZT( 1, 0, 2); ZT( 1, 1, 2); ZT( 1, 2, 2);
ZT( 2,-1, 2); ZT( 2, 0, 2); ZT( 2, 1, 2); ZT( 2, 2, 2);
-
+
return ret;
/*
a=(1.0f-cos(a*3.1415927))*0.5f;
b=(1.0f-cos(b*3.1415927))*0.5f;
-
+
// We don't perform this on the time axis, otherwise we won't
// get smooth motion
//c=(1.0f-cos(c*3.1415927))*0.5f;
-
+
float d=1.0-a;
float e=1.0-b;
float f=1.0-c;
-
+
int x2=x+1,y2=y+1,t2=t+1;
-
+
return
(*this)(subseed,x,y,t)*(d*e*f)+
(*this)(subseed,x2,y,t)*(a*e*f)+
}
else
{
-
+
float a=xf-x;
float b=yf-y;
float c=tf-t;
-
+
float d=1.0-a;
float e=1.0-b;
float f=1.0-c;
-
+
int x2=x+1,y2=y+1,t2=t+1;
-
+
return
(*this)(subseed,x,y,t)*(d*e*f)+
(*this)(subseed,x2,y,t)*(a*e*f)+
{
int pool_[POOL_SIZE];
int seed_;
-
+
int x_mask, y_mask, t_mask;
-
+
public:
-
+
void set_seed(int x);
int get_seed()const { return seed_; }
-
- float operator()(int subseed,int x,int y=0, int t=0)const;
- float operator()(int smooth,int subseed,float x,float y=0, float t=0)const;
+
+ float operator()(int subseed,int x,int y=0, int t=0)const;
+ float operator()(int smooth,int subseed,float x,float y=0, float t=0)const;
};
/* === E N D =============================================================== */
//png_size_t size;
/* Note that libpng has already taken care of
the CRC handling */
-
+
/* put your code here. Return one of the
following: */
-
+
//return (-n); /* chunk had an error */
return (0); /* did not recognize */
//return (n); /* success */
png_mptr::png_mptr(const char *file_name)
{
filename=file_name;
-
+
/* Open the file pointer */
FILE *file = fopen(file_name, "rb");
if (!file)
throw strprintf("Unable to physically open %s",file_name);
return;
}
-
-
+
+
/* Make sure we are dealing with a PNG format file */
png_byte header[PNG_CHECK_BYTES];
fread(header, 1, PNG_CHECK_BYTES, file);
throw strprintf("This (\"%s\") doesn't appear to be a PNG file",file_name);
return;
}
-
-
+
+
png_structp png_ptr = png_create_read_struct
(PNG_LIBPNG_VER_STRING, (png_voidp)this,
&png_mptr::png_out_error, &png_mptr::png_out_warning);
return;
}
-
-
+
+
png_init_io(png_ptr, file);
png_set_sig_bytes(png_ptr,PNG_CHECK_BYTES);
synfig::info("PNG: Image gamma is %f",fgamma);
png_set_gamma(png_ptr, gamma().get_gamma(), fgamma);
}
-
-
+
+
/*
if (setjmp(png_jmpbuf(png_ptr)))
{
return;
}
*/
-
+
png_set_read_user_chunk_fn(png_ptr, this, &png_mptr::read_chunk_callback);
-
-
+
+
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING|PNG_TRANSFORM_STRIP_16, NULL);
int bit_depth,color_type,interlace_type, compression_type,filter_method;
png_uint_32 width,height;
-
+
png_get_IHDR(png_ptr, info_ptr, &width, &height,
&bit_depth, &color_type, &interlace_type,
&compression_type, &filter_method);
-
+
png_bytep *row_pointers=new png_bytep[height];
row_pointers = png_get_rows(png_ptr, info_ptr);
int x;
*/
}
break;
-
+
case PNG_COLOR_TYPE_RGB_ALPHA:
DEBUGPOINT();
for(y=0;y<surface_buffer.get_h();y++)
*/
}
break;
-
+
case PNG_COLOR_TYPE_GRAY:
for(y=0;y<surface_buffer.get_h();y++)
for(x=0;x<surface_buffer.get_w();x++)
}
DEBUGPOINT();
-
+
// \fixme These shouldn't be uncommented, but for some
// reason, they crash the program. I will have to look into this
// later. This is a memory leak, but it shouldn't be too bad.
-
+
/*
png_read_end(png_ptr, end_info);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
filename=Filename;
buffer=NULL;
ready=false;
- color_buffer=0;
+ color_buffer=0;
}
png_trgt::~png_trgt()
png_trgt::start_frame(synfig::ProgressCallback *callback)
{
int w=desc.get_w(),h=desc.get_h();
-
+
if(file && file!=stdout)
fclose(file);
if(filename=="-")
newfilename(filename),
ext(find(filename.begin(),filename.end(),'.'),filename.end());
newfilename.erase(find(newfilename.begin(),newfilename.end(),'.'),newfilename.end());
-
+
newfilename+=etl::strprintf("%04d",imagecount)+ext;
file=fopen(newfilename.c_str(),"wb");
if(callback)callback->task(newfilename);
file=fopen(filename.c_str(),"wb");
if(callback)callback->task(filename);
}
-
+
if(!file)
return false;
-
+
delete [] buffer;
buffer=new unsigned char[4*w];
fclose(file);
return false;
}
-
+
info_ptr= png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
return false;
}
-
+
if (setjmp(png_jmpbuf(png_ptr)))
{
synfig::error("Unable to setup longjump");
// Write the gamma
//png_set_gAMA(png_ptr, info_ptr,1.0/gamma().get_gamma());
png_set_gAMA(png_ptr, info_ptr,gamma().get_gamma());
-
+
// Write the physical size
png_set_pHYs(png_ptr,info_ptr,round_to_int(desc.get_x_res()),round_to_int(desc.get_y_res()),PNG_RESOLUTION_METER);
-
+
// Output any text info along with the file
png_text comments[]=
{
{ PNG_TEXT_COMPRESSION_NONE, "Software", "SYNFIG" },
};
png_set_text(png_ptr,info_ptr,comments,sizeof(comments)/sizeof(png_text));
-
+
png_write_info_before_PLTE(png_ptr, info_ptr);
png_write_info(png_ptr, info_ptr);
ready=true;
SmartFILE file(fopen(filename.c_str(),"rb"));
if(!file)
{
- if(cb)cb->error("pp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str()));
+ if(cb)cb->error("pp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str()));
return false;
}
int w,h;
float divisor;
-
+
if(fgetc(file.get())!='P' || fgetc(file.get())!='6')
{
- if(cb)cb->error("pp_mptr::GetFrame(): "+strprintf(_("%s was not in PPM format"),filename.c_str()));
+ if(cb)cb->error("pp_mptr::GetFrame(): "+strprintf(_("%s was not in PPM format"),filename.c_str()));
return false;
}
-
+
fgetc(file.get());
fscanf(file.get(),"%d %d\n",&w,&h);
fscanf(file.get(),"%f",&divisor);
fgetc(file.get());
-
+
int x;
int y;
surface.set_wh(w,h);
filename=Filename;
passthru=ppm::New((tmp_dir+"temp.ppm").c_str());
paramfile=NULL;
-
+
}
bsd_mpeg1::~bsd_mpeg1()
bsd_mpeg1::set_rend_desc(RendDesc *given_desc)
{
if(paramfile)
- fclose(paramfile);
-
-
+ fclose(paramfile);
+
+
paramfile=fopen((tmp_dir+"temp.param").c_str(),"wt");
int bitrate=150; // kbytes per second
int buffer_drift=50; // bitrate drift (in kbytes per second)
-
+
bitrate*=8*1024;
buffer_drift*=8*1024;
-
+
fprintf(paramfile,
"PATTERN IBBPBBPBBPBBPBBP\n"
"OUTPUT %s\n"
"BUFFER_SIZE %d\n"
,filename.c_str(),bitrate,buffer_drift);
float fps=given_desc->get_frame_rate();
-
+
// Valid framerates:
// 23.976, 24, 25, 29.97, 30, 50 ,59.94, 60
-
+
if(fps <24.0)
{
fprintf(paramfile,"FRAME_RATE 23.976\n");
fprintf(paramfile,"FRAME_RATE 59.94\n");
given_desc->set_frame_rate(59.94);
}
-
+
// Make sure that the width and height
// are multiples of 8
given_desc->set_w((given_desc->get_w()+4)/8*8);
given_desc->set_h((given_desc->get_h()+4)/8*8);
-
+
if(!passthru->set_rend_desc(given_desc))
return false;
-
+
desc=*given_desc;
fprintf(paramfile,
fclose(paramfile);
paramfile=NULL;
-
+
return true;
}
virtual void end_frame();
virtual ~bsd_mpeg1();
-
+
virtual unsigned char * start_scanline(int scanline);
virtual bool end_scanline(void);
ppm::start_frame(synfig::ProgressCallback *callback)
{
int w=desc.get_w(),h=desc.get_h();
-
+
if(filename=="-")
{
if(callback)callback->task(strprintf("(stdout) %d",imagecount).c_str());
newfilename(filename),
ext(find(filename.begin(),filename.end(),'.'),filename.end());
newfilename.erase(find(newfilename.begin(),newfilename.end(),'.'),newfilename.end());
-
+
newfilename+=etl::strprintf("%04d",imagecount)+ext;
file=SmartFILE(fopen(newfilename.c_str(),"wb"));
if(callback)callback->task(newfilename);
file=SmartFILE(fopen(filename.c_str(),"wb"));
if(callback)callback->task(filename);
}
-
+
if(!file)
return false;
-
+
fprintf(file.get(), "P6\n");
fprintf(file.get(), "%d %d\n", w, h);
- fprintf(file.get(), "%d\n", 255);
-
+ fprintf(file.get(), "%d\n", 255);
+
delete [] buffer;
buffer=new unsigned char[3*w];
delete [] color_buffer;
color_buffer=new Color[desc.get_w()];
-
+
return true;
}
return false;
convert_color_format(buffer, color_buffer, desc.get_w(), PF_RGB, gamma());
-
+
if(!fwrite(buffer,1,desc.get_w()*3,file.get()))
return false;
// Set up our surface
surface.set_wh(desc.get_w(),desc.get_h());
-
+
return true;
}
if(surface.get_w()>x+1)
surface[y][x+1]+=error * ((float)7/(float)16);
}
-
+
fputc(i,file.get());
}
-
-
+
+
// Create new super-sampled surface
Surface sm_surface(w/2,h/2);
for(y=0;y<h;y+=2)
}
fputc(i,file.get());
}
-
+
// Output V channel
for(y=0;y<sm_surface.get_h();y++)
for(x=0;x<sm_surface.get_w();x++)
}
fputc(i,file.get());
}
-
+
// Flush out the frame
fflush(file.get());
}
synfig::String filename;
synfig::SmartFILE file;
synfig::Surface surface;
-
+
bool dithering;
public:
cerr<<"unable to open /tmp/tmp.synfig.size"<<endl;
return false;
}
-
+
int w=4,h=4,x,y;
char bleh[500];
-
+
fscanf(sizefile,"%s %s %dx%d",bleh,bleh,&w,&h);
-
+
cerr<<strprintf("w:%d, h:%d, time:%f",w,h,time)<<endl;
fseek(rgbfile,2047+3*8,SEEK_CUR);
surface.set_wh(w,h);
b=(unsigned char)fgetc(rgbfile),
g=(unsigned char)fgetc(rgbfile),
r=(unsigned char)fgetc(rgbfile);
-
+
surface[h-y-1][x]=Color(
(float)r/255.0,
(float)g/255.0,
1.0
);
}
-
+
fclose(rgbfile);
fclose(sizefile);
-
+
return true;
}
public:
private:
String filename;
-
+
public:
mplayer_mptr(const char *filename);
~mplayer_mptr();
namespace synfig {
class GUID;
class ValueNode;
-
+
struct Activepoint : public UniqueID
{
private:
etl::loose_handle<ValueNode> parent_;
int index;
-
+
public:
//! Time of the activepoint
Time time;
-
+
//! Priority
int priority;
//! Does this activepoint turn the entry on, or off?
bool state;
-
+
bool operator<(const Activepoint& rhs) { return time<rhs.time; }
bool operator<(const Time& rhs) { return time<rhs; }
-
+
Activepoint(const Time &time, const bool &state, int p=0): time(time), priority(p),state(state) { }
Activepoint() { }
-
+
const Time& get_time()const { return time; }
void set_time(const Time& x) { time=x; }
void set_priority(int x) { priority=x; }
const etl::loose_handle<ValueNode> &get_parent_value_node()const { return parent_; }
- void set_parent_value_node(const etl::loose_handle<ValueNode> &x) { parent_=x; }
-
+ void set_parent_value_node(const etl::loose_handle<ValueNode> &x) { parent_=x; }
+
int get_parent_index()const { return index; }
void set_parent_index(int x) { index=x; }
-
+
GUID get_guid()const;
}; // END of struct ValueNode_BLine::Activepoint
void set_split_tangent_flag(bool x=true) { split_tangent_=x; }
void reverse();
-
+
}; // END of class BLinePoint
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
/* === M E T H O D S ======================================================= */
Point Blur::operator ()(const Point &pos) const
-{
+{
Point blurpos(pos);
-
+
switch(type)
{
case CROSS:
blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1];
break;
}
-
+
return blurpos;
}
Tmp2=SR0+Tmp1;
SR0=Tmp1;
surface[y][x]=(SC0[x]+Tmp2)/4;
- SC0[x]=Tmp2;
+ SC0[x]=Tmp2;
}
}
delete [] SC0;
SR0=Tmp1;
Tmp1=SR1+Tmp2;
SR1=Tmp2;
-
+
// Column Machine
Tmp2=SC0[x]+Tmp1;
SC0[x]=Tmp1;
if(y&&x)
surface[y-1][x-1]=(SC1[x]+Tmp2)/16;
SC1[x]=Tmp2;
- }
+ }
}
delete [] SC0;
T SR[n-1];
T *SC[n-1];
-
+
for(i=0;i<n-1;i++)
{
SC[i]=new T[w+half_n];
}
//THE GOOD ONE!!!!!!!!!
-bool Blur::operator ()(const Surface &surface,
- const Vector &resolution,
+bool Blur::operator ()(const Surface &surface,
+ const Vector &resolution,
Surface &out) const
{
int w = surface.get_w(),
h = surface.get_h();
-
+
if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
-
+
const Real pw = resolution[0]/w,
ph = resolution[1]/h;
-
+
int halfsizex = (int) (abs(size[0]*.5/pw) + 1),
- halfsizey = (int) (abs(size[1]*.5/ph) + 1);
-
+ halfsizey = (int) (abs(size[1]*.5/ph) + 1);
+
int x,y;
-
+
SuperCallback blurcall(cb,0,5000,5000);
-
+
Surface worksurface(w,h);
-
+
//synfig::info("Blur: check surface = %s", surface_valid(surface)?"true":"false");
-
+
// Premultiply the alpha
for(y=0;y<h;y++)
{
worksurface[y][x] = a;
}
}
-
+
switch(type)
{
case Blur::DISC: // D I S C ----------------------------------------------------------
- {
+ {
int bw = halfsizex;
int bh = halfsizey;
-
+
if(size[0] && size[1] && w*h>2)
{
int x2,y2;
Surface tmp_surface(worksurface);
-
+
for(y=0;y<h;y++)
{
for(x=0;x<w;x++)
//accumulate all the pixels in an ellipse of w,h about the current pixel
Color color=Color::alpha();
int total=0;
-
+
for(y2=-bh;y2<=bh;y2++)
{
for(x2=-bw;x2<=bw;x2++)
float tmp_y=(float)y2/bh;
tmp_x*=tmp_x;
tmp_y*=tmp_y;
-
+
//ignore if it's outside of the disc
if( tmp_x+tmp_y>1.0)
continue;
-
+
//cap the pixel indices to inside the surface
int u= x+x2,
v= y+y2;
-
+
if( u < 0 ) u = 0;
if( u >= w ) u = w-1;
-
+
if( v < 0 ) v = 0;
if( v >= h ) v = h-1;
-
+
//accumulate the color, and # of pixels added in
color += tmp_surface[v][u];
total++;
}
}
-
+
//blend the color with the original color
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
worksurface[y][x]=color/total;
}
break;
}
-
+
//if we don't qualify for disc blur just use box blur
}
{
//horizontal part
//synfig::info("Blur: Starting Box blur (surface valid %d)", (int)surface_valid(worksurface));
-
+
Surface temp_surface;
temp_surface.set_wh(w,h);
-
+
if(size[0])
{
int length = halfsizex;
length=std::max(1,length);
-
+
//synfig::info("Blur: hbox blur work -> temp %d", length);
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
//synfig::info("Blur: hbox finished");
-
+
//vertical part
//Surface temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
if(size[1])
{
int length = halfsizey;
length = std::max(1,length);
-
+
//synfig::info("Blur: vbox blur temp -> work %d",length);
etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
}
else worksurface = temp_surface;
//synfig::info("Blur: vbox finished");
-
+
//blend with the original surface
/*int x,y;
for(y=0;y<h;y++)
break;
case Blur::FASTGAUSSIAN: // F A S T G A U S S I A N ----------------------------------------------
- {
+ {
//fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
-
+
/* 1 2 1
2 4 2
1 2 1
*/
-
+
Surface temp_surface;
temp_surface.set_wh(w,h);
-
+
//Surface temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
//horizontal part
if(size[0])
{
Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
length=std::max(1.0,length);
-
+
//two box blurs produces: 1 2 1
etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=worksurface;
-
+
//vertical part
if(size[1])
{
Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
length=std::max(1.0,length);
-
+
//two box blurs produces: 1 2 1 on the horizontal 1 2 1
etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=temp_surface2;
-
+
/*int x,y;
for(y=0;y<h;y++)
{
//horizontal part
Surface temp_surface;
temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[0])
{
int length = halfsizex;
length = std::max(1,length);
-
+
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
-
+
//vertical part
Surface temp_surface2;
temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[1])
{
int length = halfsizey;
length = std::max(1,length);
-
+
etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
}
else temp_surface2 = worksurface;
-
+
//blend the two together
int x,y;
Real pw = (Real)w/(resolution[0]);
Real ph = (Real)h/(resolution[1]);
-
+
Surface temp_surface;
Surface *gauss_surface;
-
+
//synfig::warning("Didn't crash yet b1");
-
+
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
gauss_surface = &worksurface;
/*else
//synfig::warning("Didn't crash yet b2");
//int i = 0;
-
+
while(bw&&bh)
{
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
GuassianBlur_2x2(*gauss_surface);
bw--,bh--;
}
-
+
//synfig::warning("Didn't crash yet bi - %d",i++);
}
while(bw)
}
// Scale up the alpha
-
+
//be sure the surface is of the correct size
//surface->set_wh(renddesc.get_w(),renddesc.get_h());
out.set_wh(w,h);
-
+
//divide out the alpha
for(y=0;y<h;y++)
{
else out[y][x]=Color::alpha();
}
}
-
+
//we are FRIGGGIN done....
blurcall.amount_complete(100,100);
-
+
return true;
}
-bool Blur::operator ()(const surface<float> &surface,
- const Vector &resolution,
+bool Blur::operator ()(const surface<float> &surface,
+ const Vector &resolution,
surface<float> &out) const
{
int w = surface.get_w(),
h = surface.get_h();
-
+
if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
-
+
const Real pw = resolution[0]/w,
ph = resolution[1]/h;
-
+
int halfsizex = (int) (abs(size[0]*.5/pw) + 1),
- halfsizey = (int) (abs(size[1]*.5/ph) + 1);
+ halfsizey = (int) (abs(size[1]*.5/ph) + 1);
int x,y;
-
+
SuperCallback blurcall(cb,0,5000,5000);
-
+
etl::surface<float> worksurface(surface);
-
+
//don't need to premultiply because we are dealing with ONLY alpha
-
+
switch(type)
{
case Blur::DISC: // D I S C ----------------------------------------------------------
- {
+ {
int bw = halfsizex;
int bh = halfsizey;
-
+
if(size[0] && size[1] && w*h>2)
{
int x2,y2;
etl::surface<float> tmp_surface(worksurface);
-
+
for(y=0;y<h;y++)
{
for(x=0;x<w;x++)
//accumulate all the pixels in an ellipse of w,h about the current pixel
float a = 0;
int total=0;
-
+
for(y2=-bh;y2<=bh;y2++)
{
for(x2=-bw;x2<=bw;x2++)
float tmp_y=(float)y2/bh;
tmp_x*=tmp_x;
tmp_y*=tmp_y;
-
+
//ignore if it's outside of the disc
if( tmp_x+tmp_y>1.0)
continue;
-
+
//cap the pixel indices to inside the surface
int u= x+x2,
v= y+y2;
-
+
if( u < 0 ) u = 0;
if( u >= w ) u = w-1;
-
+
if( v < 0 ) v = 0;
if( v >= h ) v = h-1;
-
+
//accumulate the color, and # of pixels added in
a += tmp_surface[v][u];
total++;
}
}
-
+
//blend the color with the original color
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
worksurface[y][x]=a/total;
}
break;
}
-
+
//if we don't qualify for disc blur just use box blur
}
//horizontal part
etl::surface<float> temp_surface;
temp_surface.set_wh(w,h);
-
+
if(size[0])
{
int length = halfsizex;
length=std::max(1,length);
-
+
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
-
+
//vertical part
//etl::surface<float> temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
if(size[1])
{
int length = halfsizey;
etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
}
else worksurface = temp_surface;
-
+
//blend with the original surface
/*int x,y;
for(y=0;y<h;y++)
break;
case Blur::FASTGAUSSIAN: // F A S T G A U S S I A N ----------------------------------------------
- {
+ {
//fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
-
+
/* 1 2 1
2 4 2
1 2 1
*/
-
+
etl::surface<float> temp_surface;
temp_surface.set_wh(w,h);
-
+
//etl::surface<float> temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
//horizontal part
if(size[0])
{
Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
length=std::max(1.0,length);
-
+
//two box blurs produces: 1 2 1
etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=worksurface;
-
+
//vertical part
if(size[1])
{
Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
length=std::max(1.0,length);
-
+
//two box blurs produces: 1 2 1 on the horizontal 1 2 1
etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=temp_surface2;
-
+
/*int x,y;
for(y=0;y<h;y++)
{
//horizontal part
etl::surface<float> temp_surface;
temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[0])
{
int length = halfsizex;
length = std::max(1,length);
-
+
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
-
+
//vertical part
etl::surface<float> temp_surface2;
temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[1])
{
int length = halfsizey;
length = std::max(1,length);
-
+
etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
}
else temp_surface2 = worksurface;
-
+
//blend the two together
int x,y;
Real pw = (Real)w/(resolution[0]);
Real ph = (Real)h/(resolution[1]);
-
+
//etl::surface<float> temp_surface;
etl::surface<float> *gauss_surface;
-
+
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
gauss_surface = &worksurface;
/*else
float *SC1=new float[w+2];
float *SC2=new float[w+2];
float *SC3=new float[w+2];
-
+
memset(SC0,0,(w+2)*sizeof(float));
memset(SC0,0,(w+2)*sizeof(float));
memset(SC0,0,(w+2)*sizeof(float));
memset(SC0,0,(w+2)*sizeof(float));
//int i = 0;
-
+
while(bw&&bh)
- {
+ {
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
if(bw>=4 && bh>=4)
bw--,bh--;
}
}
-
+
while(bw)
{
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
bw--;
}
}
-
+
while(bh)
{
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
default:
break;
}
-
+
//be sure the surface is of the correct size
//surface->set_wh(renddesc.get_w(),renddesc.get_h());
out.set_wh(w,h);
-
+
//divide out the alpha - don't need to cause we rock
out = worksurface;
-
+
//we are FRIGGGIN done....
blurcall.amount_complete(100,100);
-
+
return true;
}
/* === C L A S S E S & S T R U C T S ======================================= */
class synfig::ProgressCallback;
-
+
class Blur
{
public:
CROSS =2,
GAUSSIAN =3,
DISC =4,
-
+
FORCE_DWORD = 0x8fffffff
};
synfig::Point & set_size(const synfig::Point &v) { return (size = v); }
const synfig::Point & get_size() const { return size; }
synfig::Point & get_size() { return size; }
-
+
int & set_type(const int &t) { return (type = t); }
const int & get_type() const { return type; }
int & get_type() { return type; }
-
+
Blur() {}
Blur(const synfig::Point &s, int t, synfig::ProgressCallback *callb=0):size(s), type(t), cb(callb) {}
Blur(synfig::Real sx, synfig::Real sy, int t, synfig::ProgressCallback *callb = 0): size(sx,sy), type(t), cb(callb) {}
-
+
//Parametric Blur
synfig::Point operator ()(const synfig::Point &p) const;
synfig::Point operator ()(synfig::Real x, synfig::Real y) const;
-
+
//Surface based blur
// input surface can be the same as output surface,
// though both have to be the same size
bool operator ()(const synfig::Surface &surface, const synfig::Vector &resolution, synfig::Surface &out) const;
-
+
bool operator ()(const etl::surface<float> &surface, const synfig::Vector &resolution, etl::surface<float> &out) const;
//bool operator ()(const etl::surface<unsigned char> &surface, const synfig::Vector &resolution, etl::surface<unsigned char> &out) const;
};
{
Layer::Handle layer(front());
//if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
-
+
erase(begin());
//if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
}
// would just continue going when polled
// for a color.
CanvasBase::push_back(Layer::Handle());
-
+
changed();
}
{
static const char bad_chars[]=" :#@$^&()*";
unsigned int i;
-
+
if(!x.empty() && x[0]>='0' && x[0]<='9')
return false;
-
+
for(i=0;i<sizeof(bad_chars);i++)
if(x.find_first_of(bad_chars[i])!=string::npos)
return false;
{
if(is_inline() && parent_)
throw runtime_error("Inline Canvas cannot have an ID");
-
+
if(!valid_id(x))
throw runtime_error("Invalid ID");
id_=x;
void
Canvas::set_time(Time t)const
-{
+{
if(is_dirty_ || !get_time().is_equal(t))
- {
+ {
#if 0
if(is_root())
{
// ...questionable
const_cast<Canvas&>(*this).cur_time_=t;
-
+
is_dirty_=false;
get_context().set_time(t);
}
if(x.get()==this)
return String();
-
+
if(parent()==x.get())
return get_id();
-
+
String id;
-
+
const Canvas* canvas=this;
-
+
for(;!canvas->is_root();canvas=canvas->parent().get())
id=':'+canvas->get_id()+id;
-
+
if(x && get_root()!=x->get_root())
{
//String file_name=get_file_name();
//String file_path=x->get_file_path();
-
+
String file_name;
if(is_absolute_path(get_file_name()))
file_name=etl::relative_path(x->get_file_path(),get_file_name());
else
file_name=get_file_name();
-
+
// If the path of X is inside of file_name,
// then remove it.
//if(file_name.size()>file_path.size())
// if(file_path==String(file_name,0,file_path.size()))
// file_name.erase(0,file_path.size()+1);
-
+
id=file_name+'#'+id;
}
{
if(is_inline() && parent_)
return parent_->find_value_node(id);
-
+
if(id.empty())
throw Exception::IDNotFound("Empty ID");
String value_node_id(id,id.rfind(':')+1);
if(canvas_id.empty())
canvas_id=':';
-
+
return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
}
if(id.find_first_of(':',0)!=string::npos)
throw Exception::BadLinkName("Bad character");
-
+
try
{
//DEBUGPOINT();
if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
throw Exception::IDNotFound("add_value_node()");
-
+
//DEBUGPOINT();
throw Exception::IDAlreadyExists(id);
}
{
//DEBUGPOINT();
x->set_id(id);
-
+
x->set_parent_canvas(this);
-
+
if(!value_node_list_.add(x))
{
synfig::error("Unable to add ValueNode");
throw std::runtime_error("Unable to add ValueNode");
}
//DEBUGPOINT();
-
+
return;
}
}
}
catch(Exception::IDNotFound)
{
- x->set_id(id);
+ x->set_id(id);
return;
}
if(is_inline() && parent_)
return parent_->remove_value_node(x);
// throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
-
+
if(!x)
throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
-
+
if(!value_node_list_.erase(x))
throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
//x->set_parent_canvas(0);
-
+
x->set_id("");
}
{
if(is_inline() && parent_)
return parent_->surefind_canvas(id);
-
+
if(id.empty())
return this;
-
+
// If the ID contains a "#" character, then a filename is
- // expected on the left side.
+ // expected on the left side.
if(id.find_first_of('#')!=string::npos)
{
// If '#' is the first character, remove it
// and attempt to parse the ID again.
if(id[0]=='#')
return surefind_canvas(String(id,1));
-
+
//! \todo This needs alot more optimization
String file_name(id,0,id.find_first_of('#'));
String external_id(id,id.find_first_of('#')+1);
file_name=unix_to_local_path(file_name);
-
+
Canvas::Handle external_canvas;
-
+
// If the composition is already open, then use it.
if(externals_.count(file_name))
external_canvas=externals_[file_name];
throw Exception::FileNotFound(file_name);
externals_[file_name]=external_canvas;
}
-
+
return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
}
-
+
// If we do not have any resolution, then we assume that the
// request is for this immediate canvas
if(id.find_first_of(':')==string::npos)
{
Children::iterator iter;
-
+
// Search for the image in the image list,
// and return it if it is found
for(iter=children().begin();iter!=children().end();iter++)
if(id==(*iter)->get_id())
return *iter;
-
+
// Create a new canvas and return it
//synfig::warning("Implicitly creating canvas named "+id);
return new_child_canvas(id);
}
-
- // If the first character is the seperator, then
+
+ // If the first character is the seperator, then
// this references the root canvas.
if(id[0]==':')
return get_root()->surefind_canvas(string(id,1));
// Now we know that the requested Canvas is in a child
- // of this canvas. We have to find that canvas and
+ // of this canvas. We have to find that canvas and
// call "find_canvas" on it, and return the result.
-
+
String canvas_name=string(id,0,id.find_first_of(':'));
-
+
Canvas::Handle child_canvas=surefind_canvas(canvas_name);
return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
return this;
// If the ID contains a "#" character, then a filename is
- // expected on the left side.
+ // expected on the left side.
if(id.find_first_of('#')!=string::npos)
{
// If '#' is the first character, remove it
// and attempt to parse the ID again.
if(id[0]=='#')
return find_canvas(String(id,1));
-
+
//! \todo This needs alot more optimization
String file_name(id,0,id.find_first_of('#'));
String external_id(id,id.find_first_of('#')+1);
-
+
file_name=unix_to_local_path(file_name);
-
+
Canvas::Handle external_canvas;
-
+
// If the composition is already open, then use it.
if(externals_.count(file_name))
external_canvas=externals_[file_name];
throw Exception::FileNotFound(file_name);
externals_[file_name]=external_canvas;
}
-
+
return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
}
-
+
// If we do not have any resolution, then we assume that the
// request is for this immediate canvas
if(id.find_first_of(':')==string::npos)
{
Children::const_iterator iter;
-
+
// Search for the image in the image list,
// and return it if it is found
for(iter=children().begin();iter!=children().end();iter++)
if(id==(*iter)->get_id())
return *iter;
-
+
throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
}
-
- // If the first character is the seperator, then
+
+ // If the first character is the seperator, then
// this references the root canvas.
if(id.find_first_of(':')==0)
return get_root()->find_canvas(string(id,1));
// Now we know that the requested Canvas is in a child
- // of this canvas. We have to find that canvas and
+ // of this canvas. We have to find that canvas and
// call "find_canvas" on it, and return the result.
-
+
String canvas_name=string(id,0,id.find_first_of(':'));
-
+
Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
add_child(x.get());
-
+
LooseHandle correct_canvas(this);
//while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
Layer::LooseHandle loose_layer(x);
-
+
x->signal_added_to_group().connect(
sigc::bind(
sigc::mem_fun(
{
if(!(*iter)->get_group().empty())
remove_group_pair((*iter)->get_group(),(*iter));
-
+
// HACK: We really shouldn't be wiping
// out these signals entirely. We should
// only be removing the specific connections
(*iter)->signal_removed_from_group().clear();
if(!op_flag_)remove_child(iter->get());
-
+
CanvasBase::erase(iter);
if(!op_flag_)changed();
}
else
{
name=get_id()+"_CLONE";
-
+
throw runtime_error("Cloning of non-inline canvases is not yet suported");
}
-
+
Handle canvas(new Canvas(name));
-
+
if(is_inline())
{
canvas->is_inline_=true;
{
if(is_inline_ && parent_)
{
-
+
}
-
+
id_="inline";
is_inline_=true;
parent_=parent;
{
parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
}
-
+
rend_desc()=parent->rend_desc();
}
assert(parent);
//if(parent->is_inline())
// return create_inline(parent->parent());
-
+
Handle canvas(new Canvas("inline"));
canvas->set_inline(parent);
return canvas;
// Create a new canvas
children().push_back(create());
Canvas::Handle canvas(children().back());
-
+
canvas->set_id(id);
canvas->parent_=this;
canvas->rend_desc()=rend_desc();
if(child_canvas->parent() && !child_canvas->is_inline())
throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
-
+
if(!valid_id(id))
throw runtime_error("Invalid ID");
-
+
try
{
find_canvas(id);
children().push_back(child_canvas);
child_canvas->parent_=this;
}
-
+
return child_canvas;
}
{
if(is_inline() && parent_)
return parent_->remove_child_canvas(child_canvas);
-
+
if(child_canvas->parent_!=this)
throw runtime_error("Given child does not belong to me");
-
+
if(find(children().begin(),children().end(),child_canvas)==children().end())
throw Exception::IDNotFound(child_canvas->get_id());
-
+
children().remove(child_canvas);
child_canvas->parent_=0;
return dirname(file_name_);
}
-
+
String
Canvas::get_meta_data(const String& key)const
{
for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
ret.push_back(iter->first);
-
+
return ret;
}
std::vector< std::pair<float,Layer::Handle> > sort_list;
int i;
-
+
// Go ahead and start romping through the canvas to paste
for(iter=context,i=0;*iter;iter++,i++)
{
Layer::Handle layer=*iter;
float z_depth(layer->get_z_depth()*1.0001+i);
-
+
// If the layer isn't active, don't worry about it
if(!layer->active())
continue;
optimize_layers(paste_canvas->get_sub_canvas()->get_context(),sub_canvas);
//#define SYNFIG_OPTIMIZE_PASTE_CANVAS 1
-#ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
+#ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
Canvas::iterator sub_iter;
// Determine if we can just remove the paste canvas
- // altogether
+ // altogether
if(paste_canvas->get_blend_method()==Color::BLEND_COMPOSITE && paste_canvas->get_amount()==1.0f && paste_canvas->get_zoom()==0 && paste_canvas->get_time_offset()==0 && paste_canvas->get_origin()==Point(0,0))
try{
for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
{
Layer* layer=sub_iter->get();
-
+
// any layers that deform end up breaking things
// so do things the old way if we run into anything like this
if(!dynamic_cast<Layer_NoDeform*>(layer))
if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
throw int();
}
-
+
// It has turned out that we don't need a paste canvas
// layer, so just go ahead and add all the layers onto
// the current stack and be done with it
dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_do_not_muck_with_time(false);
layer=new_layer;
}
-
+
sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
- //op_canvas->push_back_simple(layer);
+ //op_canvas->push_back_simple(layer);
}
-
+
//sort_list.sort();
stable_sort(sort_list.begin(),sort_list.end());
std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
{
const_iterator i = begin(),
iend = end();
-
+
for(; i != iend; ++i)
{
const Node::time_set &tset = (*i)->get_times();
return group_db_.size();
}
-
+
void
Canvas::add_group_pair(String group, etl::handle<Layer> layer)
{
signal_group_added()(group);
else
signal_group_changed()(group);
-
+
signal_group_pair_added()(group,layer);
if(is_inline() && parent_)
{
if(is_inline() && parent_)
return parent_->rename_group(old_name,new_name);
-
+
{
std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
iter=group_db_.find(old_name);
rename_group(iter->first,name);
}
}
-
+
std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
std::set<etl::handle<Layer> >::iterator iter;
-
+
for(iter=layers.begin();iter!=layers.end();++iter)
{
(*iter)->remove_from_group(old_name);
class Context;
class GUID;
-
+
/*! \class Canvas
** \todo writeme
*/
//! List containing any child Canvases
/*! \see children() */
- Children children_;
-
+ Children children_;
+
//! Render Description for Canvas
/*! \see rend_desc() */
RendDesc desc_;
//! \writeme
mutable std::map<String,Handle> externals_;
-
+
//! This flag is set if this canvas is "inline"
bool is_inline_;
mutable bool is_dirty_;
-
+
bool op_flag_;
-
+
//! Layer Group database
- std::map<String,std::set<etl::handle<Layer> > > group_db_;
+ std::map<String,std::set<etl::handle<Layer> > > group_db_;
/*
-- ** -- S I G N A L S -------------------------------------------------------
private:
//! Group Added
- sigc::signal<void,String> signal_group_added_;
+ sigc::signal<void,String> signal_group_added_;
//! Group Removed
- sigc::signal<void,String> signal_group_removed_;
-
+ sigc::signal<void,String> signal_group_removed_;
+
//! Group Changed
- sigc::signal<void,String> signal_group_changed_;
+ sigc::signal<void,String> signal_group_changed_;
sigc::signal<void,String,etl::handle<synfig::Layer> > signal_group_pair_added_;
sigc::signal<void,String,etl::handle<synfig::Layer> > signal_group_pair_removed_;
//! Layers Reordered
- sigc::signal<void,int*> signal_layers_reordered_;
-
+ sigc::signal<void,int*> signal_layers_reordered_;
+
//! RendDesc Changed
- sigc::signal<void> signal_rend_desc_changed_;
-
+ sigc::signal<void> signal_rend_desc_changed_;
+
//! ID Changed
- sigc::signal<void> signal_id_changed_;
+ sigc::signal<void> signal_id_changed_;
//! Dirty
- //sigc::signal<void> signal_dirty_;
+ //sigc::signal<void> signal_dirty_;
//! FileName Changed
- sigc::signal<void> signal_file_name_changed_;
+ sigc::signal<void> signal_file_name_changed_;
//! Metadata Changed
- sigc::signal<void, String> signal_meta_data_changed_;
+ sigc::signal<void, String> signal_meta_data_changed_;
//! Key-Specific meta data changed signals
std::map<String, sigc::signal<void> > signal_map_meta_data_changed_;
//! ValueBasenode Changed
- sigc::signal<void, etl::handle<ValueNode> > signal_value_node_changed_;
+ sigc::signal<void, etl::handle<ValueNode> > signal_value_node_changed_;
- sigc::signal<void, etl::handle<ValueNode>, etl::handle<ValueNode> > signal_value_node_child_added_;
+ sigc::signal<void, etl::handle<ValueNode>, etl::handle<ValueNode> > signal_value_node_child_added_;
- sigc::signal<void, etl::handle<ValueNode>, etl::handle<ValueNode> > signal_value_node_child_removed_;
+ sigc::signal<void, etl::handle<ValueNode>, etl::handle<ValueNode> > signal_value_node_child_removed_;
/*
-- ** -- S I G N A L I N T E R F A C E -------------------------------------
//! Group Removed
sigc::signal<void,String>& signal_group_removed() { return signal_group_removed_; }
-
+
//! Group Changed
sigc::signal<void,String>& signal_group_changed() { return signal_group_changed_; }
//! Layers Reordered
sigc::signal<void,int*>& signal_layers_reordered() { return signal_layers_reordered_; }
-
+
//! RendDesc Changed
sigc::signal<void>& signal_rend_desc_changed() { return signal_rend_desc_changed_; }
-
+
//! ID Changed
sigc::signal<void>& signal_id_changed() { return signal_id_changed_; }
//! File name Changed
sigc::signal<void>& signal_file_name_changed();
-
+
//! Metadata Changed
sigc::signal<void, String>& signal_meta_data_changed() { return signal_meta_data_changed_; }
//! Metadata Changed
sigc::signal<void>& signal_meta_data_changed(const String& key) { return signal_map_meta_data_changed_[key]; }
-
- sigc::signal<void, etl::handle<ValueNode> >& signal_value_node_changed() { return signal_value_node_changed_; }
+
+ sigc::signal<void, etl::handle<ValueNode> >& signal_value_node_changed() { return signal_value_node_changed_; }
//! Dirty
sigc::signal<void>& signal_dirty() { return signal_changed(); }
//! Returns the set of layers in group
std::set<etl::handle<Layer> > get_layers_in_group(const String&group);
-
+
//! Gets all the groups
std::set<String> get_groups()const;
-
+
//! Gets the number of groups in this canvas
int get_group_count()const;
//! Sets the ID of the canvas
void set_id(const String &x);
-
+
//! Returns the data string for the given meta data key
String get_meta_data(const String& key)const;
LooseHandle parent()const { return parent_; }
LooseHandle get_root()const;
-
+
//! Returns a list of all child canvases in this canvas
std::list<Handle> &children() { return children_; }
//! Gets the filename (with path)
String get_file_name()const;
-
+
//! Creates a new child canvas, and returns its handle
Handle new_child_canvas();
const_reverse_iterator rbegin()const;
etl::handle<Layer> &back();
-
+
void push_back(etl::handle<Layer> x);
void push_front(etl::handle<Layer> x);
void insert(iterator iter,etl::handle<Layer> x);
void erase(iterator iter);
-
+
const etl::handle<Layer> &back()const;
void set_inline(LooseHandle parent);
static Handle create();
static Handle create_inline(Handle parent);
-
+
Handle clone(const GUID& deriv_guid=GUID())const;
private:
namespace synfig {
class Layer;
-
+
typedef std::deque< etl::handle< Layer > > CanvasBase;
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
const float
u(get_u()),
v(get_v());
-
+
return set_uv(b*u-a*v,a*u+b*v);
//return YUV(get_y(),b*u-a*v,a*u+b*v,get_a());
//*/
Color::clamped_negative()const
{
Color ret=*this;
-
+
if(ret.a_==0)
return alpha();
// if a_arc==0.0
//if(fabsf(a_src)<COLOR_EPSILON) return dest;
-
+
// Scale the source and destination by their alpha values
src*=a_src;
dest*=a_dest;
-
+
dest=src + dest*(1.0f-a_src);
-
+
a_dest=a_src + a_dest*(1.0f-a_src);
// if a_dest!=0.0
//if(fabsf(amount-1.0f)<COLOR_EPSILON)return src;
Color out;
-
+
float a_out((src.get_a()-bg.get_a())*amount+bg.get_a());
-
+
// if a_out!=0.0
if(fabsf(a_out)>COLOR_EPSILON)
// if(a_out>COLOR_EPSILON || a_out<-COLOR_EPSILON)
blendfunc_BRIGHTEN(Color &a,Color &b,float amount)
{
const float alpha(a.get_a()*amount);
-
+
if(b.get_r()<a.get_r()*alpha)
b.set_r(a.get_r()*alpha);
if(b.get_b()<a.get_b()*alpha)
b.set_b(a.get_b()*alpha);
-
+
return b;
}
blendfunc_DARKEN(Color &a,Color &b,float amount)
{
const float alpha(a.get_a()*amount);
-
+
if(b.get_r()>(a.get_r()-1.0f)*alpha+1.0f)
b.set_r((a.get_r()-1.0f)*alpha+1.0f);
if(b.get_b()>(a.get_b()-1.0f)*alpha+1.0f)
b.set_b((a.get_b()-1.0f)*alpha+1.0f);
-
+
return b;
}
// This causes DIVIDE to bias toward positive values, but the effect is
// really neglegable. There is a reason why we use COLOR_EPSILON--we
// want the change to be imperceptable.
-
+
b.set_r(((b.get_r()/(a.get_r()+COLOR_EPSILON))-b.get_r())*(amount)+b.get_r());
b.set_g(((b.get_g()/(a.get_g()+COLOR_EPSILON))-b.get_g())*(amount)+b.get_g());
b.set_b(((b.get_b()/(a.get_b()+COLOR_EPSILON))-b.get_b())*(amount)+b.get_b());
{
Color temp(b);
temp.set_uv(a.get_u(),a.get_v());
- return (temp-b)*amount*a.get_a()+b;
+ return (temp-b)*amount*a.get_a()+b;
}
static Color
a.set_r(1.0-(1.0f-a.get_r())*(1.0f-b.get_r()));
a.set_g(1.0-(1.0f-a.get_g())*(1.0f-b.get_g()));
a.set_b(1.0-(1.0f-a.get_b())*(1.0f-b.get_b()));
-
+
return blendfunc_ONTO(a,b,amount);
}
static Color
blendfunc_OVERLAY(Color &a,Color &b,float amount)
-{
+{
if(amount<0) a=~a, amount=-amount;
Color rm;
rs.set_b(1.0-(1.0f-a.get_b())*(1.0f-b.get_b()));
Color& ret(a);
-
+
ret.set_r(a.get_r()*rs.get_r() + (1.0-a.get_r())*rm.get_r());
ret.set_g(a.get_g()*rs.get_g() + (1.0-a.get_g())*rm.get_g());
ret.set_b(a.get_b()*rs.get_b() + (1.0-a.get_b())*rm.get_b());
#endif
}
#endif
-
+
/*
if(!a.is_valid()&&b.is_valid())
return b;
#endif
}
*/
-
+
// No matter what blend method is being used,
// if the amount is equal to zero, then only B
// will shine through
if(fabsf(amount)<=COLOR_EPSILON)return b;
-
+
assert(type<BLEND_END);
-
+
const static blendfunc vtable[BLEND_END]=
{
- blendfunc_COMPOSITE,
+ blendfunc_COMPOSITE,
blendfunc_STRAIGHT,
blendfunc_BRIGHTEN,
blendfunc_DARKEN,
blendfunc_OVERLAY,
blendfunc_STRAIGHT_ONTO,
};
-
+
return vtable[type](a,b,amount);
}
bool is_valid()const
{ return !isnan(r_) && !isnan(g_) && !isnan(b_) && !isnan(a_); }
-
+
Color premult_alpha() const
{
return Color (r_*a_, g_*a_, b_*a_, a_);
}
-
+
Color demult_alpha() const
{
if(a_)
g_(c.g_),
b_(c.b_) { }
-
+
//! Copy constructor
Color(const Color& c):
a_(c.a_),
r_(c.r_),
g_(c.g_),
b_(c.b_) { }
-
+
#ifdef USE_HALF_TYPE
friend class ColorAccumulator;
//! Convert constructor
return *this;
}*/
//Color& operator=(const Color &c) { memcpy((void*)this, (const void*)&c, sizeof(Color)); return *this; }
-
+
//! Returns the RED component
const value_type& get_r()const { return r_; }
//! Returns the amount of opacity (alpha)
const value_type& get_a()const { return a_; }
-
+
//! Synonym for get_a(). \see get_a()
const value_type& get_alpha()const { return get_a(); }
//! Sets the opacity (alpha) to \a x
Color& set_a(const value_type& x) { a_ = x; return *this; }
-
+
//! Synonym for set_a(). \see set_a()
Color& set_alpha(const value_type& x) { return set_a(x); }
(float)get_b()*EncodeYUV[0][2];
}
-
+
//! Returns U component of chromanance
float
get_u() const
//! Sets color luminance
Color& set_y(const float &y) { return set_yuv(y,get_u(),get_v()); }
-
+
//! Set U component of chromanance
Color& set_u(const float &u) { return set_yuv(get_y(),u,get_v()); }
-
+
//! Set V component of chromanance
Color& set_v(const float &v) { return set_yuv(get_y(),get_u(),v); }
-
+
//! Set the U and V components of chromanance
Color& set_uv(const float& u, const float& v) { return set_yuv(get_y(),u,v); }
-
+
//! Sets the color's saturation
/*! \see get_s() */
Color&
{
float u(get_u()), v(get_v());
const float s(sqrt(u*u+v*v));
- if(s)
+ if(s)
{
u=(u/s)*x;
v=(v/s)*x;
//! Synonym for get_hue(). \see get_hue()
Angle get_uv_angle() const { return get_hue(); }
-
+
//! Sets the color's hue
/*! \see get_hue() */
Color&
//! Synonym for set_hue(). \see set_hue()
Color& set_uv_angle(const Angle& theta) { return set_hue(theta); }
-
+
//! Rotates the chromanance vector by amount specified by \a theta
Color& rotate_uv(const Angle& theta)
{
const float a(Angle::sin(theta).get()), b(Angle::cos(theta).get());
const float u(get_u()), v(get_v());
-
+
return set_uv(b*u-a*v,a*u+b*v);
}
-
+
//! Sets the luminance (\a y) and chromanance (\a s and \a theta).
/*! \param y Luminance
** \param s Saturation
//! Clamps a color so that its values are in range. Ignores attempting to visualize negative colors.
Color clamped()const;
-
+
//! Clamps a color so that its values are in range.
Color clamped_negative()const;
static inline Color cyan() { return Color(0,1,1); }
static inline Color yellow() { return Color(1,1,0); }
//@}
-
+
//! \writeme
enum BlendMethod
{
BLEND_OVERLAY=20, //!< \writeme
BLEND_DIFFERENCE=18, //!< \writeme
BLEND_HARD_LIGHT=17, //!< \writeme
-
+
//! Deprecated
BLEND_ALPHA_BRIGHTEN=14, //!< If A is less opaque than B, use A
BLEND_ALPHA_DARKEN=15, //!< If A is more opaque than B, use B
BLEND_ALPHA_OVER=19,//!< multiply alphas and then straight blends that using the amount
BLEND_STRAIGHT_ONTO=21,//!< \writeme
-
+
BLEND_END=22 //!< \internal
};
/* Other */
static Color blend(Color a, Color b,float amount,BlendMethod type=BLEND_COMPOSITE);
-
+
static bool is_onto(BlendMethod x)
{
return x==BLEND_BRIGHTEN
//! Returns the amount of opacity (alpha)
const value_type& get_a()const { return a_; }
-
+
//! Synonym for get_a(). \see get_a()
const value_type& get_alpha()const { return get_a(); }
//! Sets the opacity (alpha) to \a x
ColorAccumulator& set_a(const value_type& x) { a_ = x; return *this; }
-
+
//! Synonym for set_a(). \see set_a()
ColorAccumulator& set_alpha(const value_type& x) { return set_a(x); }
};
inline PixelFormat operator|(PixelFormat lhs, PixelFormat rhs)
{ return static_cast<PixelFormat>((int)lhs|(int)rhs); }
-
+
inline PixelFormat operator&(PixelFormat lhs, PixelFormat rhs)
{ return static_cast<PixelFormat>((int)lhs&(int)rhs); }
#define FLAGS(x,y) (((x)&(y))==(y))
++chan;
if(FLAGS(x,PF_RAW_COLOR))
chan=sizeof(Color);
-
+
return chan;
}
int alpha=(int)((FLAGS(pf,PF_A_INV)?(-(float)color.get_a()+1):(float)color.get_a())*255);
if(alpha<0)alpha=0;
if(alpha>255)alpha=255;
-
+
if(FLAGS(pf,PF_ZA|PF_A_START|PF_Z_START))
{
if(FLAGS(pf,PF_Z_START))
*out++=static_cast<unsigned char>(alpha);
if(FLAGS(pf,PF_Z_START))
*out++/*=(unsigned char)(color.GetZ()*255.0f)*/;
-
+
}
if(FLAGS(pf,PF_GRAY))
*out++=static_cast<unsigned char>(gamma.b_F32_to_U8(color.get_b()));
}
}
-
+
if(FLAGS(pf,PF_ZA))
{
if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
color.set_b((float)*out++/255);
}
}
-
+
if(FLAGS(pf,PF_ZA))
{
if(!FLAGS(pf,PF_Z_START) && FLAGS(pf,PF_Z))
Context::get_color(const Point &pos)const
{
Context context(*this);
-
+
while(!context->empty())
- {
+ {
// If this layer is active, then go
// ahead and break out of the loop
if((*context)->active())
break;
-
+
// Otherwise, we want to keep searching
// till we find either an active layer,
// or the end of the layer list
Context::get_full_bounding_rect()const
{
Context context(*this);
-
+
while(!context->empty())
- {
+ {
// If this layer is active, then go
// ahead and break out of the loop
if((*context)->active())
break;
-
+
// Otherwise, we want to keep searching
// till we find either an active layer,
// or the end of the layer list
-
+
-
-
+
at each minus we must record all the info for that which we are worried about...
each layer can do work before or after the other work is done... so both values must be recorded...
*/
{
#ifdef SYNFIG_PROFILE_LAYERS
String layer_name(curr_layer);
-
+
//sum the pre-work done by layer above us... (curr_layer is layer above us...)
if(depth>0)
{
#endif
const Rect bbox(renddesc.get_rect());
-
+
Context context(*this);
for(;!(context)->empty();++context)
{
// then move on to next layer
if(!(*context)->active())
continue;
-
+
const Rect layer_bounds((*context)->get_bounding_rect());
-
+
// If the box area is less than zero
// then move on to next layer
if(layer_bounds.area()<=0.0000000000001)
continue;
-
+
// If the boxes do not intersect
// then move on to next layer
if(!(layer_bounds && bbox))
continue;
-
+
// Break out of the loop--we have found a good layer
break;
}
surface->set_wh(renddesc.get_w(),renddesc.get_h());
surface->clear();
#ifdef SYNFIG_PROFILE_LAYERS
- profile_timer.reset();
+ profile_timer.reset();
#endif
return true;
}
try {
RWLock::ReaderLock lock((*context)->get_rw_lock());
-
+
#ifdef SYNFIG_PROFILE_LAYERS
-
+
//go down one layer :P
depth++;
curr_layer=(*context)->get_name(); //make sure the layer inside is referring to the correct layer outside
profile_timer.reset(); // +
bool ret((*context)->accelerated_render(context+1,surface,quality,renddesc, cb));
-
+
//post work for the previous layer
time_table[curr_layer]+=profile_timer(); //-
if(run_table.count(curr_layer))run_table[curr_layer]++;
depth--;
curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
-
+
//print out the table it we're done...
if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
profile_timer.reset(); //+
catch(...)
{
synfig::error("Context::accelerated_render(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
- throw;
+ throw;
}
}
{
Context context(*this);
while(!(context)->empty())
- {
+ {
// If this layer is active, then go
// ahead and break out of the loop
if((*context)->active() && !(*context)->dirty_time_.is_equal(time))
break;
-
+
// Otherwise, we want to keep searching
// till we find either an active layer,
// or the end of the layer list
{
Layer::ParamList params;
Layer::DynamicParamList::const_iterator iter;
-
+
for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
params[iter->first]=(*iter->second)(time);
-
+
(*context)->set_param_list(params);
(*context)->set_time(context+1,time);
/*
Context context(*this);
while(!(context)->empty())
- {
+ {
// If this layer is active, then go
// ahead and break out of the loop
if((*context)->active())
break;
-
+
// Otherwise, we want to keep searching
// till we find either an active layer,
// or the end of the layer list
{
Layer::ParamList params;
Layer::DynamicParamList::const_iterator iter;
-
+
for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
params[iter->first]=(*iter->second)(time);
-
+
(*context)->set_param_list(params);
(*context)->set_time(context+1,time,pos);
Context::hit_check(const Point &pos)const
{
Context context(*this);
-
+
while(!context->empty())
- {
+ {
// If this layer is active, then go
// ahead and break out of the loop
if((*context)->active())
break;
-
+
// Otherwise, we want to keep searching
// till we find either an active layer,
// or the end of the layer list
class Layer;
class Time;
class Rect;
-
+
/*! \class Context
** \todo writeme
** \see Layer, Canvas */
Context() { }
Context(const CanvasBase::const_iterator &x):CanvasBase::const_iterator(x) { }
-
+
Context operator=(const CanvasBase::const_iterator &x)
{ return CanvasBase::const_iterator::operator=(x); }
-
+
/*! \todo write me */
Color get_color(const Point &pos)const;
etl::handle<Layer> hit_check(const Point &point)const;
}; // END of class Context
-
+
}; // END of namespace synfig
-
+
/* === E N D =============================================================== */
#endif
/* === E N T R Y P O I N T ================================================= */
-Real synfig::find_closest(const etl::bezier<Point> &curve, const Point &point,
+Real synfig::find_closest(const etl::bezier<Point> &curve, const Point &point,
float step, Real *dout, float *tout)
{
#if 0
if(dout) *dout=dist;
if(tout) *tout=time;
return time;
-#else
+#else
Real d,closest = 1.0e50;
- float t,time,closestt = -1;
+ float t,time,closestt = -1;
Vector p0,p1,end;
-
+
if(dout && *dout > 0)
closest = *dout;
{
p1 = curve(t);
d = line_point_distsq(p0,p1,point,time);
-
+
if(d<closest)
{
closest=d;
closestt = t-step + time*step;//t+(time-1)*step; //time between [t-step,t]
}
}
-
+
d = line_point_distsq(p0,end,point,time);
if(d<closest)
{
{
if(tout) *tout = closestt;
}
-
+
return closest;
#endif
}
void BezHull::Bound(const etl::bezier<Point> &b)
{
#if 1
-
- //with a starting vertex, find the only vertex that has all other vertices on it's right
+
+ //with a starting vertex, find the only vertex that has all other vertices on it's right
int i,j;
int first,cur,last;
-
+
float d,ds;
-
+
Vector n,vi;
Vector::value_type deqn;
-
+
//get left most vertex
d = b[0][0];
first = 0;
if(b[i][0] < d)
{
d = b[i][0];
- first = i;
+ first = i;
}
}
cur = last = first;
size = 0;
-
+
//find the farthest point with all points on right
ds = 0;
do //should reassign cur so it won't break on first step
- {
+ {
for(i = 0; i < 4; ++i)
{
if(i == cur || i == last) continue;
-
+
//rotate vector to right to make normal
vi = -(b[i] - b[cur]).perp();
d = vi.mag_squared();
-
+
//we want only the farthest (solves the case with many points on a line)
if(d > ds)
{
d = n*b[i] - deqn;
if(d < 0) break; //we're on left, nope!
}
-
+
//everyone is on right... yay! :)
if(d >= 0)
{
//advance point and add last one into hull
p[size++] = p[last];
last = cur;
- cur = i;
+ cur = i;
}
}
}
}while(cur != first);
-
+
#else
//will work but does not keep winding order
-
+
//convex hull alg.
//build set of line segs which have no points on other side...
//start with initial normal segments
-
+
//start with single triangle
p[0] = b[0];
p[1] = b[1];
p[2] = b[2];
p[3] = b[3];
-
+
//initial reject (if point is inside triangle don't care)
{
Vector v1,v2,vp;
-
+
v1 = p[1]-p[0];
v2 = p[2]-p[0];
-
+
vp = p[3]-p[0];
float s = (vp*v1) / (v1*v1),
t = (vp*v2) / (v2*v2);
-
+
//if we're inside the triangle we don't this sissy point
if( s >= 0 && s <= 1 && t >= 0 && t <= 1 )
{
size = 3;
return;
- }
+ }
}
-
+
//expand triangle based on info...
bool line;
int index,i,j;
float ds,d;
-
+
//distance from point to vertices
line = false;
index = 0;
if(d < ds)
{
index = i;
- ds = d;
+ ds = d;
}
}
-
+
//distance to line
float t;
j = 2;
line = true;
}
}
-
+
//We don't need no stinkin extra vertex, just replace
if(!line)
{
{
//must expand volume to work with point...
// after the index then
-
+
/* Pattern:
0 - push 1,2 -> 2,3
1 - push 2 -> 3
{
p[i] = p[i-1];
}
-
+
p[index] = b[3]; //recopy b3
size = 4;
}
-
+
#endif
}
//Line Intersection
-int
-synfig::intersect(const Point &p1, const Vector &v1, float &t1,
+int
+synfig::intersect(const Point &p1, const Vector &v1, float &t1,
const Point &p2, const Vector &v2, float &t2)
{
/* Parametric intersection:
l1 = p1 + tv1, l2 = p2 + sv2
-
+
0 = p1+tv1-(p2+sv2)
group parameters: sv2 - tv1 = p1-p2
-
+
^ = transpose
invert matrix (on condition det != 0):
A[t s]^ = [p1-p2]^
-
+
A = [-v1 v2]
-
+
det = v1y.v2x - v1x.v2y
-
+
if non 0 then A^-1 = invdet * | v2y -v2x |
| v1y -v1x |
-
+
[t s]^ = A^-1 [p1-p2]^
- */
-
+ */
+
Vector::value_type det = v1[1]*v2[0] - v1[0]*v2[1];
-
+
//is determinant valid?
if(det > ERR || det < -ERR)
{
Vector p_p = p1-p2;
-
+
det = 1/det;
-
+
t1 = det*(v2[1]*p_p[0] - v2[0]*p_p[1]);
t2 = det*(v1[1]*p_p[0] - v1[0]*p_p[1]);
-
+
return 1;
}
-
+
return 0;
}
int intersect(const Rect &r, const Point &p, const Vector &v)
{
float t[4] = {0};
-
- /*get horizontal intersections and then vertical intersections
- and intersect them
-
+
+ /*get horizontal intersections and then vertical intersections
+ and intersect them
+
Vertical planes - n = (1,0)
Horizontal planes - n = (0,1)
- so if we are solving for ray with implicit line
+ so if we are solving for ray with implicit line
*/
-
- //solve horizontal
+
+ //solve horizontal
if(v[0] > ERR || v[0] < -ERR)
{
//solve for t0, t1
{
return (int)(p[1] >= r.miny && p[1] <= r.maxy);
}
-
+
//solve vertical
if(v[1] > ERR || v[1] < -ERR)
{
//polygon cliping
Vector n;
Vector::value_type nv;
-
+
Point last = bh.p[3];
for(int i = 0; i < bh.size; ++i)
{
n = (bh.p[i] - last).perp(); //rotate 90 deg.
-
+
/*
since rotated left
if n.v < 0 - going in
if(nv > ERR)
{
maxt = min(maxt,(float)((n*(p-last))/nv));
- }else
+ }else
if( nv < -ERR) //going IN
{
mint = max(mint,(float)((n*(p-last))/nv));
return 0;
}
}
-
+
last = bh.p[i];
}
-
+
return 0;
}
{
float t1=0,t2=1;
Vector v=p2-p1;
-
- /*get horizontal intersections and then vertical intersections
- and intersect them
-
+
+ /*get horizontal intersections and then vertical intersections
+ and intersect them
+
Vertical planes - n = (1,0)
Horizontal planes - n = (0,1)
- so if we are solving for ray with implicit line
+ so if we are solving for ray with implicit line
*/
-
+
//solve horizontal
if(v[0] > ERR || v[0] < -ERR)
{
//solve for t0, t1
float tt1 = (r.minx - p1[0])/v[0],
tt2 = (r.maxx - p1[0])/v[0];
-
+
//line in positive direction (normal comparisons
if(tt1 < tt2)
{
if(p1[1] < r.miny || p1[1] > r.maxy)
return 0;
}
-
+
//solve vertical
if(v[1] > ERR || v[1] < -ERR)
{
//solve for t0, t1
float tt1 = (r.miny - p1[1])/v[1],
tt2 = (r.maxy - p1[1])/v[1];
-
+
//line in positive direction (normal comparisons
if(tt1 < tt2)
{
if(op1) *op1 = p1 + v*t1;
if(op2) *op2 = p1 + v*t2;
-
+
return 1;
}
{
bezier<Point> temp;
- temp = b;
+ temp = b;
temp.set_r(0);
temp.set_s(1);
-
+
if(b.get_r() != 0)
temp.subdivide(0,&temp,b.get_r());
-
+
if(b.get_s() != 1)
temp.subdivide(&temp,0,b.get_s());
-
+
out = temp;
}
CIntersect::CIntersect()
: max_depth(10) //depth of 10 means timevalue parameters will have an approx. error bound of 2^-10
{
-}
+}
struct CIntersect::SCurve
{
float rt,st;
//float mid, //the midpoint time value on this section of the subdivided curve
// scale; //the current delta in time values this curve would be on original curve
-
+
float mag; //approximate sum of magnitudes of each edge of control polygon
Rect aabb; //Axis Aligned Bounding Box for quick (albeit less accurate) collision
SCurve() {}
SCurve(const bezier<Point> &c,float rin, float sin)
- :b(c),rt(rin),st(sin),mag(1)
+ :b(c),rt(rin),st(sin),mag(1)
{
Bound(aabb,b);
}
-
+
void Split(SCurve &l, SCurve &r) const
{
b.subdivide(&l.b,&r.b);
-
+
l.rt = rt;
r.st = st;
l.st = r.rt = (rt+st)/2;
//accept curves (and perform super detailed check for intersections)
//if the values are below tolerance
-
+
//NOTE FOR BETTERING OF ALGORITHM: SHOULD ALSO/IN-PLACE-OF CHECK MAGNITUDE OF EDGES (or approximate)
if(depthleft <= 0)
{
for(int i = 0; i < 3; ++i)
{
//intersect line segmentsssss
-
+
//solve for the y_value
Vector v = b.b[i+1] - b.b[i];
if(v[1] > ERROR && v[1] < ERROR)
{
Real xi = (p1[1] - b.b[i][1])/v[1];
-
- //and add in the turn (up or down) if it's valid
+
+ //and add in the turn (up or down) if it's valid
if(xi < p1[0]) turn += (v[1] > 0) ? 1 : -1;
}
}
-
+
return turn;
}
-
+
//subdivide the curve and continue
CIntersect::SCurve l1,r1;
b.Split(l1,r1); //subdivide left
-
+
//test each subdivision against the point
return recurse_intersect(l1,p1) + recurse_intersect(r1,p1);
}
sb.rt = 0; sb.st = 1;
sb.mag = 1; Bound(sb.aabb,sb.b);
-
- return recurse_intersect(sb,p);
+
+ return recurse_intersect(sb,p);
}
//Curve curve intersection
void CIntersect::recurse_intersect(const SCurve &left, const SCurve &right, int depth)
-{
+{
//reject curves that do not overlap with bouding boxes
if(!intersect(left.aabb,right.aabb)) return;
//accept curves (and perform super detailed check for intersections)
//if the values are below tolerance
-
+
//NOTE FOR BETTERING OF ALGORITHM: SHOULD ALSO/IN-PLACE-OF CHECK MAGNITUDE OF EDGES (or approximate)
if(depth >= max_depth)
{
//NOTE FOR IMPROVEMENT: Polish roots based on original curve with the Jacobian
// (may be too expensive to be effective)
-
+
//perform root approximation
//collide line segments
-
+
float t,s;
for(int i = 0; i < 3; ++i)
{
//We got one Jimmy
times.push_back(intersect_set::value_type(t,s));
- }
+ }
}
- }
-
+ }
+
return;
}
-
- //NOTE FOR IMPROVEMENT: only subdivide one curve and choose the one that has
+
+ //NOTE FOR IMPROVEMENT: only subdivide one curve and choose the one that has
// the highest approximated length
- //fast approximation to curve length may be hard (accurate would
- // involve 3 square roots), could sum the squares which would be
+ //fast approximation to curve length may be hard (accurate would
+ // involve 3 square roots), could sum the squares which would be
// quick but inaccurate
-
- SCurve l1,r1,l2,r2;
+
+ SCurve l1,r1,l2,r2;
left.Split(l1,r1); //subdivide left
right.Split(l2,r2); //subdivide right
-
+
//Test each cantidate against eachother
recurse_intersect(l1,l2);
recurse_intersect(l1,r2);
bool CIntersect::operator()(const bezier<Point> &c1, const bezier<Point> &c2)
{
times.clear();
-
+
//need to subdivide and check recursive bounding regions against eachother
//so track a list of dirty curves and compare compare compare
-
-
+
+
//temporary curves for subdivision
CIntersect intersector;
CIntersect::SCurve left,right;
-
- //Make sure the parameters are normalized (so we don't compare unwanted parts of the curves,
+
+ //Make sure the parameters are normalized (so we don't compare unwanted parts of the curves,
// and don't miss any for that matter)
-
+
//left curve
//Compile information about curve
clean_bez(c1,left.b);
left.rt = 0; left.st = 1;
Bound(left.aabb, left.b);
-
+
//right curve
//Compile information about right curve
clean_bez(c2,right.b);
right.rt = 0; right.st = 1;
Bound(right.aabb, right.b);
-
+
//Perform Curve intersection
intersector.recurse_intersect(left,right);
-
+
//Get information about roots (yay! :P)
return times.size() != 0;
}
int intersect_scurve(const CIntersect::SCurve &b, const Point &p)
{
//initial reject/approve etc.
-
- /*
+
+ /*
*-----------*---------
| |
| |
| |
| 1 | 2
- | |
+ | |
| |
| |
| |
*/
if(p[0] < b.aabb.minx || p[1] < b.aabb.miny || p[1] > b.aabb.maxy)
return 0;
-
+
//approve only if to the right of rect around 2 end points
{
Rect r;
r.set_point(b.b[0][0],b.b[0][1]);
r.expand(b.b[3][0],b.b[3][1]);
-
+
if(p[0] >= r.maxx && p[1] <= r.maxy && p[1] >= r.miny)
{
float df = b.b[3][1] - b.b[0][1];
-
+
return df >= 0 ? 1 : -1;
}
}
-
+
//subdivide and check again!
CIntersect::SCurve l,r;
b.Split(l,r);
int synfig::intersect(const bezier<Point> &b, const Point &p)
{
CIntersect::SCurve c(b,0,1);
-
+
return intersect_scurve(c,p);
}
namespace synfig {
//line helper functions
-inline Real line_point_distsq(const Point &p1, const Point &p2,
+inline Real line_point_distsq(const Point &p1, const Point &p2,
const Point &p, float &t)
{
Vector v,vt;
-
+
v = p2 - p1;
vt = p - p1;
-
+
t = v.mag_squared() > 1e-12 ? (vt*v)/v.mag_squared() : 0; //get the projected time value for the current line
-
- //get distance to line segment with the time value clamped 0-1
+
+ //get distance to line segment with the time value clamped 0-1
if(t >= 1) //use p+v
{
- vt += v; //makes it pp - (p+v)
+ vt += v; //makes it pp - (p+v)
t = 1;
}else if(t > 0) //use vt-proj
{
{
t = 0;
}
-
+
//else use p
return vt.mag_squared();
}
{
Point p;
Vector v;
-
+
Ray() {}
Ray(const Point &pin, const Vector &vin):p(pin), v(vin) {}
};
-/* This algorithm calculates the INTERSECTION of 2 line segments
+/* This algorithm calculates the INTERSECTION of 2 line segments
(not the closest point or anything like that, just intersection)
//parameter values returned are [0,1]
*/
-int intersect(const Point &p1, const Vector &v1, float &t1,
+int intersect(const Point &p1, const Vector &v1, float &t1,
const Point &p2, const Vector &v2, float &t2);
inline bool intersect_line_segments(const Point &a, const Point &b, float &tout,
const Point &c, const Point &d, float &sout)
{
Vector v1(b-a), v2(d-c);
-
+
//ok so treat both lines as parametric (so we can find the time values simultaneously)
float t,s;
sout = s;
return true;
}
-
- return false;
+
+ return false;
}
//Find the closest point on the curve to a point (and return it's distance, and time value)
return (r1.minx < r2.maxx) &
(r2.minx < r1.maxx) &
(r1.miny < r2.maxy) &
- (r2.miny < r1.maxy);
+ (r2.miny < r1.maxy);
}*/
//----- Convex Hull of a Bezier Curve --------------
struct BezHull
{
- Point p[4];
+ Point p[4];
int size;
-
+
void Bound(const etl::bezier<Point> &b);
};
struct SCurve;
private:
void recurse_intersect(const SCurve &left, const SCurve &right, int depth = 0);
-
+
public:
//size should be equal
typedef std::vector< std::pair<float,float > > intersect_set;
CurvePoint::CurvePoint(const BLinePoint &bpoint)
{
p = bpoint.get_vertex();
-
+
l = p + bpoint.get_tangent1()*(1/3.0f);
r = p + bpoint.get_tangent2()*(1/3.0f);
}
int curveindex;
int vertindex;
float tvalue;
-
+
ipoint *next;
ipoint *prev;
ipoint *neighbor;
-
+
int go_in; //going in = 1, coming out = -1
-
+
ipoint()
{
next = this;
prev = this;
neighbor = 0;
}
-
+
bool operator<(const ipoint &rhs) const
{
if(curveindex == rhs.curveindex)
}else return vertindex < rhs.vertindex;
}else return curveindex < rhs.curveindex;
}
-
+
bool operator >(const ipoint &rhs) const
{
return rhs < *this;
}
-
+
void insert_after(ipoint *i)
{
//from: next - next.prev
//to: next* - i - next.prev*
-
+
ipoint *bef = this,
*aft = next;
-
+
//assuming the input point is not connected to anything, we don't have to do anything with it...
bef->next = i;
i->prev = bef;
aft->prev = i;
- i->next = aft;
+ i->next = aft;
}
-
+
void insert_before(ipoint *i)
{
//from: prev.next - prev
//to: prev.next* - i - prev*
-
+
ipoint *bef = prev,
*aft = this;
-
+
//assuming the input point is not connected to anything, we don't have to do anything with it...
bef->next = i;
i->prev = bef;
aft->prev = i;
- i->next = aft;
+ i->next = aft;
}
-
+
void insert_sorted(ipoint *i)
{
ipoint *search = this;
-
+
if(*i < *this)
{
//we go forward
{
search = search->next;
}while(*i < *search && search != this); //ending conditions...
-
+
//now we insert previously...
search->insert_before(i);
}else if(*i > *this)
{
search = search->prev;
}while(*i > *search && search != this); //ending conditions...
-
+
//now we insert previously...
search->insert_after(i);
}
vector<CurveInts> c1ints;
vector<CurveInts> c2ints;
-
+
//get the intersections
void GetIntersections(const CurveSet &lhs, const CurveSet &rhs)
- {
+ {
CIntersect isect;
bezier<Point> b1,b2;
-
+
int i1,j1,ci1,s1;
int i2,j2,ci2,s2;
-
+
//clear out so everyone's happy
c1ints.clear();
c2ints.clear();
-
+
c1ints.resize(lhs.set.size());
c2ints.resize(rhs.set.size());
-
+
//loop through everyone and be happy...
-
+
//intersect each curve with each other curve, and we're good
for(ci1=0;ci1 < (int)lhs.set.size(); ++ci1)
{
b1[3] = cur1[i1].p;
b1[1] = b1[0] + cur1[j1].r/3;
b1[2] = b1[3] - cur1[i1].l/3;
-
+
for(ci2=0;ci2 < (int)rhs.set.size(); ++ci2)
{
const CurveSet::region &cur2 = rhs.set[ci2];
b2[3] = cur2[i2].p;
b2[1] = b2[0] + cur2[j2].r/3;
b2[2] = b2[3] - cur2[i2].l/3;
-
+
isect(b1,b2);
for(int index=0; index < (int)isect.times.size(); ++index)
{
//prepare basic intersection information
ipoint *ip1 = new ipoint, *ip2 = new ipoint;
-
+
//set parameters
ip1->curveindex = ci1; ip1->vertindex = j1; ip1->tvalue = isect.times[index].first;
ip2->curveindex = ci2; ip2->vertindex = j2; ip2->tvalue = isect.times[index].second;
-
+
//set neighbors
ip1->neighbor = ip2;
ip2->neighbor = ip1;
-
+
//first one just goes on end of list
c1ints[ci1].back()->insert_sorted(ip1);
- c1ints[ci1].push_back(ip1);
-
+ c1ints[ci1].push_back(ip1);
+
//second one must go in order
c2ints[ci2].back()->insert_sorted(ip2);
c2ints[ci2].push_back(ip2);
-
+
//we're all good...
}
- }
- }
- }
+ }
+ }
+ }
}
-
+
//Now figure out the containment properties of each int point
- Point p;
+ Point p;
int inside = 0;
for(int i = 0; i < (int)c1ints.size(); ++i)
{
if(c1ints[i].size() == 0) continue;
-
+
//must test insideness for the edges
ipoint *start, *iter;
start = iter = c1ints[i].front();
-
+
//i == iter->curveindex == the index of the current curve we're looking at
-
+
//set the initial insideness on the other curve...
p = lhs.set[i][iter->vertindex].p;
inside = rhs.intersect(p)%2; //if it's inside by the even odd rule
-
+
do
{
iter->go_in = inside? -1 : 1; //leaving if inside, or coming in if not
iter = iter->next;
}while(iter != start); //I hope this isn't an infinite loop!
}
-
+
//and curve 2
for(int i = 0; i < (int)c2ints.size(); ++i)
{
if(c2ints[i].size() == 0) continue;
-
+
//must test insideness for the edges
ipoint *start, *iter;
start = iter = c1ints[i].front();
-
+
//set the initial insideness on the other curve...
p = rhs.set[i][iter->vertindex].p;
inside = lhs.intersect(p)%2; //if it's inside by the even odd rule
-
+
do
{
iter->go_in = inside? -1 : 1; //leaving if inside, or coming in if not
}while(iter != start); //I hope this isn't an infinite loop!
}
}
-
+
bool ConstructSet(CurveSet &c, const CurveSet &lhs, const CurveSet &rhs, int type)
{
bool in1,in2;
-
+
switch(type)
{
case INTERSECT: //1&2
in1 = true; in2 = true;
break;
}
-
+
case UNION: //1|2
{
in1 = false; in2 = false;
break;
}
-
+
case SUBTRACT: //1-2
{
in1 = true; in2 = false;
- break;
+ break;
}
-
+
case INVSUBTRACT: //2-1
{
in1 = false; in2 = true;
break;
}
-
+
default:
{
return false;
- }
+ }
}
-
+
//traverse path based on inside flags
-
+
//fill all the paths of native stuff
set<ipoint *> ipset;
for(int ci=0; ci<(int)c1ints.size(); ++ci)
for(int i=0; i < (int)c1ints[ci].size(); ++i)
{
ipset.insert(c1ints[ci][i]);
- }
+ }
}
-
+
//
while(ipset.size() > 0)
{
//start from one point (always on curveset 1) and traverse until we find it again
ipoint *start, *iter;
start = iter = *ipset.begin();
-
+
//All the info to swap when we transition curves...
const CurveSet *cur, *other;
bool curin, otherin;
bool delcur = true;
-
+
set<ipoint *>::iterator deliter;
-
+
int ci,i1,i2,size;
float t1,t2;
-
+
CurveSet::region current;
CurvePoint cp;
-
+
cur = &lhs; other = &rhs;
curin = in1; otherin = in2;
- delcur = true;
-
+ delcur = true;
+
do
{
//remove the current iter from the set
deliter = ipset.find(iter);
if(deliter != ipset.end()) ipset.erase(deliter);
}
-
+
//go to next and accumulate information
ci = iter->curveindex;
i1 = iter->vertindex;
- t1 = iter->tvalue;
+ t1 = iter->tvalue;
iter = iter->next; //move to next and get its info
-
+
i2 = iter->vertindex;
t2 = iter->tvalue;
-
+
size = cur->set[ci].size();
-
- //record all the stuff between us...
+
+ //record all the stuff between us...
//start on an intersection - get the curve point...
-
-
+
+
//transition curves...
iter = iter->neighbor;
swap(cur,other);
swap(curin,otherin);
delcur = !delcur;
- }while(iter != start); //I hope THIS isn't an infinite loop
+ }while(iter != start); //I hope THIS isn't an infinite loop
}
-
+
return true;
}
};
{
i += set[si].size();
si--;
- }
+ }
}
}
Algorithm:
1) Inside out scheme, track when edges go into and come out of various objects etc.
-
+
+ doesn't require initial conditions
- - only works with odd-even rule
+ - only works with odd-even rule
*/
CurveSet CurveSet::operator &(const CurveSet &rhs) const
{
int inter = 0, ci,i,j,s;
bezier<Point> b;
-
+
for(ci=0; ci < (int)set.size(); ++ci)
{
const vector<CurvePoint> &curve = set[ci];
{
b[0] = curve[j].p; b[3] = curve[i].p;
b[1] = b[0] + curve[j].r/3; b[2] = b[3] - curve[i].l/3;
-
+
inter += synfig::intersect(b,p);
}
}
-
+
return inter;
}
{
class BLinePoint;
-
+
struct CurvePoint
{
Point p;
Point l,r;
-
+
CurvePoint () {}
CurvePoint(const Point &pin, const Vector &left, const Vector &right);
-
+
CurvePoint(const BLinePoint &bpoint);
};
-
-class CurveSet
+
+class CurveSet
{
bool invert; //winding order...
-
+
void CleanUp(int curve = 0);
public:
-
+
typedef std::vector<CurvePoint> region;
typedef std::vector<region> set_type;
-
+
set_type set; //specifies a region object (assumes looping)
void SetClamp(int &i, int &si);
CurveSet()
{
}
-
+
//anything supporting iterator type operations
template < typename Iterator >
CurveSet(Iterator begin, Iterator end, bool invert = false)
set.push_back(std::vector<CurvePoint>(begin,end));
CleanUp(invert);
}
-
+
CurveSet operator &(const CurveSet &rhs) const; //intersect
CurveSet operator |(const CurveSet &rhs) const; //union
CurveSet operator -(const CurveSet &rhs) const; //subtract
-
-
+
+
//Point containment
int intersect(const Point &p) const;
};
float val;
int ret(strscanf(str,"%f%n",&val,&i));
synfig::info("Distance::Distance(): ret=%d, val=%f",ret,val);
-
+
if(ret<=0)
{
// Error
}
else
value_=val;
-
+
synfig::info("Distance::Distance(): system=\"%s\"",String(str.begin()+i,str.end()).c_str());
system_=ident_system(String(str.begin()+i,str.end()));
*/
float val;
int ret(strscanf(str,"%f%n",&val,&i));
synfig::info("Distance::Distance(): ret=%d, val=%f",ret,val);
-
+
if(ret<=0)
{
// Error
return units(rend_desc);
if(target==SYSTEM_PIXELS)
return units(rend_desc)*METERS_PER_UNIT*rend_desc.get_x_res();
-
- return meters_to_system(meters(rend_desc),target);
+
+ return meters_to_system(meters(rend_desc),target);
}
-
+
Real
Distance::meters()const
{
// If it is plural, make it singular
if(str[str.size()-1]=='S')
str=synfig::String(str.begin(),str.end()-1);
-
+
if(str.empty() || str=="U" || str=="UNIT")
return SYSTEM_UNITS;
if(str=="PX" || str=="PIXEL")
return SYSTEM_CENTIMETERS;
if(str=="MM" || str=="MILLIMETER")
return SYSTEM_MILLIMETERS;
-
+
synfig::warning("Distance::ident_system(): Unknown distance system \"%s\"",x.c_str());
-
+
return SYSTEM_UNITS;
}
case SYSTEM_METERS: return "m";
case SYSTEM_MILLIMETERS: return "mm";
case SYSTEM_CENTIMETERS: return "cm";
-
+
default: throw BadSystem();
}
return synfig::String();
case SYSTEM_METERS: return _("Meters");
case SYSTEM_MILLIMETERS:return _("Millimeters");
case SYSTEM_CENTIMETERS:return _("Centimeters");
-
+
default: throw BadSystem();
}
return synfig::String();
{
public:
typedef Real value_type;
-
+
enum System
{
SYSTEM_UNITS, //!<
SYSTEM_PIXELS, //!<
-
+
SYSTEM_POINTS, //!<
SYSTEM_INCHES, //!<
SYSTEM_METERS, //!<
class BadSystem { };
-private:
+private:
value_type value_;
-
+
System system_;
-
+
public:
Distance(){ }
Distance(const value_type& value, System system):value_(value),system_(system) { }
explicit Distance(const synfig::String& string);
-
+
operator Real()const { return value_; }
Distance& operator=(const Real& rhs) { value_=rhs; return *this; }
Distance& operator=(const synfig::String& rhs);
synfig::String get_string(int digits=4)const;
-
+
const System& get_system()const { return system_; }
const Real& get()const { return value_; }
Real get(System system, const RendDesc& rend_desc)const;
-
+
void convert(System system, const RendDesc& rend_desc);
-
+
Real meters()const;
Real meters(const RendDesc& rend_desc)const;
Real units(const RendDesc& rend_desc)const;
-
+
static Real meters_to_system(Real x, System target_system);
static System ident_system(const synfig::String& str);
static synfig::String system_name(System system);
const Distance& operator-=(const float &rhs) { value_-=rhs; return *this; }
const Distance& operator*=(const float &rhs) { value_*=rhs; return *this; }
const Distance& operator/=(const float &rhs) { value_/=rhs; return *this; }
-
+
/*
template<typename U> const Time& operator+=(const U &rhs) { value_+=rhs; return *this; }
template<typename U> const Time& operator-=(const U &rhs) { value_-=rhs; return *this; }
template<typename U> Time operator-(const U &rhs)const { return value_-rhs; }
template<typename U> Time operator*(const U &rhs)const { return value_*rhs; }
template<typename U> Time operator/(const U &rhs)const { return value_/rhs; }
-
+
Time operator-()const { return -value_; }
*/
}; // END of class Distance
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
namespace Exception {
class BadLinkName : public std::runtime_error
if(x==black_level) return;
black_level=x;
-
+
// Rebuild tables
refresh_gamma_r();
refresh_gamma_g();
if(x==red_blue_level) return;
red_blue_level=x;
-
+
// Rebuild tables
refresh_gamma_r();
refresh_gamma_g();
// If nothing has changed, then don't recompute the tables
if(gamma_r==r && gamma_g==g && gamma_b==b && black_level==black && red_blue_level==red_blue)
return;
-
+
gamma_r=r;
gamma_g=g;
gamma_b=b;
float gamma_b;
float black_level;
float red_blue_level;
-
+
unsigned char table_r_U16_to_U8[65536];
unsigned char table_g_U16_to_U8[65536];
unsigned char table_b_U16_to_U8[65536];
float table_r_U8_to_F32[256];
float table_g_U8_to_F32[256];
float table_b_U8_to_F32[256];
-
+
public:
Gamma(float x=1):black_level(0) { set_gamma(x); }
float get_gamma_b()const { return gamma_b; }
float get_black_level()const { return black_level; }
float get_red_blue_level()const { return red_blue_level; }
-
+
void refresh_gamma_r();
void refresh_gamma_g();
void refresh_gamma_b();
-
+
const unsigned char &r_U16_to_U8(int i)const { return table_r_U16_to_U8[i]; }
const unsigned char &g_U16_to_U8(int i)const { return table_g_U16_to_U8[i]; }
const unsigned char &b_U16_to_U8(int i)const { return table_b_U16_to_U8[i]; }
float g_F32_to_F32(float x)const { return static_cast<float>(pow(x,gamma_g)*(1.0f-black_level)+black_level); }
float b_F32_to_F32(float x)const { return static_cast<float>(pow(x,gamma_b)*(1.0f-black_level)+black_level); }
}; // END of class Gamma
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
virtual bool error(const String &task) { return true; }
virtual bool warning(const String &task) { return true; }
virtual bool amount_complete(int current, int total) { return true; }
-
+
virtual bool valid() const { return true; }
};
virtual bool error(const String &task) { if(cb)return cb->error(task); return true; }
virtual bool warning(const String &task) { if(cb)return cb->warning(task); return true; }
virtual bool amount_complete(int cur, int total) { if(cb)return cb->amount_complete(start+cur*w/total,tot); return true; }
-
+
virtual bool valid() const { return cb != 0; }
};
// it will sort an inverse sorted list at ~O(N*N).
void
synfig::Gradient::sort()
-{
+{
stable_sort(begin(),end());
/*
iterator iter;
iterator iter2,next;
-
+
for(iter=begin();iter!=end();iter++)
{
for(next=iter, iter2=next--;iter2!=begin();iter2=next--)
//insert(next,*iter);
//erase(iter);
iter_swap(next,iter);
-
+
continue;
}
else
{
weight=0;
return Color::alpha();
- }
+ }
if(color1.pos>=begin && color2.pos<end)
{
weight=color2.pos-color1.pos;
weight=0;
return Color::alpha();
-
+
// assert(0);
}
-
+
Color
synfig::Gradient::operator()(const Real &x,float supersample)const
{
supersample=-supersample;
if(supersample>2.0)
supersample=2.0f;
-
+
float begin_sample(x-supersample*0.5);
float end_sample(x+supersample*0.5);
if(size()==1 || end_sample<=front().pos || isnan(x))
return front().color;
-
+
if(begin_sample>=back().pos)
return back().color;
if(begin_sample<=front().pos)
begin_sample=front().pos;
*/
-
+
const_iterator iter,next;
/*
//optimizize...
Real left = x-supersample/2, right = x+supersample/2;
-
+
if(left < front().pos) left = front().pos;
if(right > back().pos) right = back().pos;
-
+
//find using binary search...
const_iterator iterl,iterr;
-
+
//the binary search should give us the values BEFORE the point we're looking for...
iterl = binary_find(begin(),end(),left);
iterr = binary_find(iterl,end(),right);
-
+
//now integrate over the range of left to right...
-
+
if(iterl == iterr)
{
iterr++; //let's look at the next one shall we :)
-
+
//interpolate neighboring colors
const Real one = iterr->pos - iterl->pos;
const Real lambda = (x - iterl->pos)/one;
-
+
//(1-l)iterl + (l)iterr
return iterl->color.premult_alpha()*(1-lambda) + iterr->color.premult_alpha()*lambda;
-
+
//return Color::blend(iterr->color,iterl->color,lambda,Color::BLEND_STRAIGHT);
}else
{
//itegration madness
const_iterator i = iterl, ie = iterr+1;
Real wlast = left;
-
+
ColorAccumulator clast,cwork;
{
const Real lambda = (x - iterl->pos)/(iterr->pos - iterl->pos);
-
+
//premultiply because that's the form in which we can combine things...
clast = iterl->color.premult_alpha()*(1-lambda) + iterr->color.premult_alpha()*lambda;
//Color::blend((i+1)->color,i->color,(left - i->pos)/((i+1)->pos - i->pos),Color::BLEND_STRAIGHT);
}
-
+
ColorAccumulator accum = 0;
-
+
//loop through all the trapezoids and integrate them as we go...
// area of trap = (yi + yi1)*(xi1 - xi)
- // yi = clast, xi = wlast, yi1 = i->color, xi1 = i->pos
-
+ // yi = clast, xi = wlast, yi1 = i->color, xi1 = i->pos
+
for(;i<=iterr; wlast=i->pos,clast=i->color.premult_alpha(),++i)
{
const Real diff = i->pos - wlast;
accum += (cwork + clast)*diff;
}
}
-
+
{
- const_iterator ibef = i-1;
+ const_iterator ibef = i-1;
const Real diff = right - ibef->pos;
-
+
if(diff > 0)
{
const Real lambda = diff/(i->pos - ibef->pos);
cwork = ibef->color.premult_alpha()*(1-lambda) + i->color.premult_alpha()*lambda;
-
+
accum += (cwork + clast)*diff; //can probably optimize this more... but it's not too bad
}
}
-
+
accum /= supersample; //should be the total area it was sampled over...
return accum.demult_alpha();
}*/
-
+
next=begin(),iter=next++;
-
+
//add for optimization
next = binary_find(begin(),end(),(Real)begin_sample);
- iter = next++;
-
+ iter = next++;
+
//! As a future optimization, this could be performed faster
//! using a binary search.
for(;iter<end();iter=next++)
// CPoints. So, we need to calculate our coverage amount.
ColorAccumulator pool(Color::alpha());
float divisor(0.0),weight(0);
-
+
const_iterator iter2,next2;
iter2=iter;
if(iter==begin() && iter->pos>x)
divisor+=weight;
}
}
-
+
next2=iter;
iter2=next2++;
while(iter2->pos<=end_sample)
divisor+=weight;
iter2=next2++;
}
-
+
if(divisor && pool.get_a() && pool.is_valid())
{
/*
for(iter=begin();iter<end();iter++)
{
float new_dist;
-
+
if(prev_pos==iter->pos)
new_dist=(abs(x-iter->pos-0.00001));
else
new_dist=(abs(x-iter->pos));
-
+
if(new_dist>dist)
{
iter--;
/*
const_iterator iter;
float dist(100000000);
-
+
// This algorithm requires a sorted list.
for(iter=begin();iter<end();iter++)
{
synfig::Gradient::find(const UniqueID &id)
{
iterator iter;
-
+
for(iter=begin();iter<end();iter++)
{
if(id==*iter)
return iter;
}
-
+
throw Exception::NotFound("synfig::Gradient::find(): Unable to find UniqueID in gradient");
}
-
+
synfig::Gradient::const_iterator
synfig::Gradient::find(const UniqueID &id)const
{
const_iterator iter;
-
+
for(iter=begin();iter<end();iter++)
{
if(id==*iter)
return iter;
}
-
+
throw Exception::NotFound("synfig::Gradient::find()const: Unable to find UniqueID in gradient");
}
{
Real pos;
Color color;
-
+
bool operator<(const GradientCPoint &rhs)const { return pos<rhs.pos; }
bool operator<(const Real &rhs)const { return pos<rhs; }
-
+
GradientCPoint() { }
GradientCPoint(const Real &pos, const Color &color):pos(pos),color(color) { }
}; // END of class GradientCPoint
-
+
/*! \class Gradient
** \brief Color Gradient Class
*/
public:
typedef GradientCPoint CPoint;
private:
-
+
public:
Gradient() { }
-
+
//! Two-Tone Color Gradient Convience Constructor
Gradient(const Color &c1, const Color &c2);
//! You should call this function after changing stuff.
void sort();
-
+
Color operator()(const Real &x, float supersample=0)const;
//! Returns the iterator of the CPoint closest to \a x
//! Returns the iterator of the CPoint with UniqueID \a id
iterator find(const UniqueID &id);
-
+
//! Returns the const_iterator of the CPoint with UniqueID \a id
const_iterator find(const UniqueID &id)const;
}; // END of class Gradient
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
{
next=x;
}
-
+
unsigned long i32()
{
static const unsigned long a(1664525);
static const unsigned long c(1013904223);
-
+
return next=next*a+c;
}
float f()
{
static const float m(int(65535));
-
+
return float(i16())/m;
}
-
+
unsigned long operator()(const unsigned long& m)
{
if(m==65536)
{
//subtractive_rng _c(clock());
unsigned short* data(reinterpret_cast<unsigned short *>(&x));
- data[0]=_a(65536);
- data[1]=_a(65536);
- data[2]=_a(65536);
- data[3]=_a(65536);
+ data[0]=_a(65536);
+ data[1]=_a(65536);
+ data[2]=_a(65536);
+ data[3]=_a(65536);
}
#else
static void get_rand_long_long(uint64_t &x)
{
_GUID* guid(reinterpret_cast<_GUID*>(&x));
- CoCreateGuid(guid);
+ CoCreateGuid(guid);
}
#else
synfig::GUID
synfig::GUID::hasher(const String& str)
-{
+{
#ifdef HASH_MAP_H
hash<const char*> string_hash_;
const unsigned int seed(
seed=(seed>>(32-(i%24)))^(seed<<(i%24))
}
#endif
-
+
GUID_RNG random(seed);
GUID ret(0);
ret.data.u_32.a=random(~(unsigned int)0);
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
class GUID
{
union {
uint64_t a;
uint64_t b;
} u_64;
-
+
} data;
-
+
public:
GUID()
- { make_unique(); }
+ { make_unique(); }
GUID(const GUID& x):data(x.data)
{ }
GUID(const int i){assert(!i); data.u_64.a=0;data.u_64.b=0;}
GUID(const String& str);
-
+
static GUID zero() { return GUID(0); }
static GUID hasher(const String& str);
static GUID hasher(int i);
operator bool()const { return data.u_32.a||data.u_32.b||data.u_32.c||data.u_32.d; }
-
+
uint64_t get_hi()const { return data.u_64.a; }
uint64_t get_lo()const { return data.u_64.b; }
uint64_t get_hi_lo()const { return data.u_32.b; }
uint64_t get_lo_hi()const { return data.u_32.c; }
uint64_t get_lo_lo()const { return data.u_32.d; }
-
+
void make_unique();
String get_string()const;
-
+
bool operator==(const GUID& rhs)const
{ return data.u_64.a==rhs.data.u_64.a && data.u_64.b==rhs.data.u_64.b; }
bool operator!=(const GUID& rhs)const
return *this;
}
GUID operator^(const GUID& rhs)const { return GUID(*this)^=rhs; }
-
+
//! Operator '%' (alt-xor)
/*! A % B != B % A. */
GUID& operator%=(const GUID& rhs)
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
class GUIDSet : public
#ifdef HASH_SET_H
std::set<synfig::GUID>
#endif
{
}; // END of class GUIDSet
-
+
};
/* === E N D =============================================================== */
synfig::error(_("Importer::open(): Cannot open empty filename"));
return 0;
}
-
+
// If we already have an importer open under that filename,
// then use it instead.
if(__open_importers->count(filename))
//synfig::info("Found importer already open, using it...");
return (*__open_importers)[filename];
}
-
+
if(find(filename.begin(),filename.end(),'.')==filename.end())
{
synfig::error(_("Importer::open(): Couldn't find extension"));
return 0;
}
-
+
String ext=string(filename.begin()+filename.find_last_of('.')+1,filename.end());
std::transform(ext.begin(),ext.end(),ext.begin(),&::tolower);
-
-
+
+
if(!Importer::book().count(ext))
{
synfig::error(_("Importer::open(): Unknown file type -- ")+ext);
return 0;
}
-
+
try {
Importer::Handle importer;
importer=Importer::book()[ext](filename.c_str());
typedef Importer* (*Factory)(const char *filename);
typedef std::map<String,Factory> Book;
static Book* book_;
-
+
static Book& book();
-
+
static bool subsys_init();
static bool subsys_stop();
Gamma& gamma() { return gamma_; }
const Gamma& gamma()const { return gamma_; }
-
+
virtual ~Importer();
//! Gets a frame and puts it into \a surface
/* === C L A S S E S & S T R U C T S ======================================= */
-namespace synfig {
+namespace synfig {
enum Interpolation
{
{
//DEBUGPOINT();
//synfig::info("PRE-SORT:");
- //dump();
+ //dump();
sort(begin(),end());
//synfig::info("POST-SORT:");
//dump();
*/
}
}
-
+
throw Exception::NotFound(strprintf("KeyframeList::find(): Can't find next Keyframe %s",x.get_string().c_str()));
}
Time time_;
String desc_;
GUID guid_;
-
+
public:
Keyframe();
~Keyframe();
void set_time(Time x) { time_=x; }
-
+
Time get_time()const { return time_; }
void set_description(String x) { desc_=x; }
-
+
String get_description()const { return desc_; }
const GUID& get_guid()const { return guid_; }
using UniqueID::operator==;
using UniqueID::operator!=;
using UniqueID::operator=;
-
+
bool operator<(const Keyframe &rhs)const { return time_<rhs.time_; }
bool operator<(const Time &rhs)const { return time_<rhs; }
const_iterator find(const Time &x)const;
const_iterator find_next(const Time &x)const;
const_iterator find_prev(const Time &x)const;
-
+
void find_prev_next(const Time& time, Time &prev, Time &next)const;
void insert_time(const Time& location, const Time& delta);
void dump()const;
- void sync();
+ void sync();
};
//typedef std::list<Keyframe> KeyframeList;
{
return Layer::LooseHandle(new Layer_Mime(name));
}
-
+
Layer* layer(book()[name].factory());
return Layer::LooseHandle(layer);
}
remove_child(dynamic_param_list_.begin()->second.get());
dynamic_param_list_.erase(dynamic_param_list_.begin());
}
-
+
remove_from_all_groups();
-
+
parent_death_connect_.disconnect();
begin_delete();
}
if(description_!=x)
{
description_=x;
- signal_description_changed_();
+ signal_description_changed_();
}
}
if(previous==value_node)
return true;
-
+
dynamic_param_list_[param]=ValueNode::Handle(value_node);
-
+
if(previous)
remove_child(previous.get());
-
+
add_child(value_node.get());
-
+
if(!value_node->is_exported() && get_canvas())
{
value_node->set_parent_canvas(get_canvas());
}
-
+
changed();
return true;
}
Layer::clone(const GUID& deriv_guid) const
{
if(!book().count(get_name())) return 0;
-
+
//Layer *ret = book()[get_name()].factory();//create(get_name()).get();
Handle ret = create(get_name()).get();
-
+
ret->group_=group_;
//ret->set_canvas(get_canvas());
ret->set_description(get_description());
ret->set_active(active());
ret->set_guid(get_guid()^deriv_guid);
-
+
//ret->set_param_list(get_param_list());
// Process the parameter list sothat
// we can duplicate any inlinecanvases
{
if(dynamic_param_list().count(iter->first)==0 && iter->second.get_type()==ValueBase::TYPE_CANVAS)
{
-
+
// This parameter is a canvas. We need a close look.
Canvas::Handle canvas(iter->second.get(Canvas::Handle()));
if(canvas->is_inline())
continue;
}
}
-
+
// This is a normal parameter,go ahead and set it.
ret->set_param(iter->first, iter->second);
}
-
+
// Duplicate the dynamic paramlist, but only the exported data nodes
DynamicParamList::const_iterator iter;
for(iter=dynamic_param_list().begin();iter!=dynamic_param_list().end();++iter)
continue;
}
}
-
+
if(iter->second->is_exported())
ret->connect_dynamic_param(iter->first,iter->second);
else
}
//ret->set_canvas(0);
-
+
return ret;
}
{
DynamicParamList::const_iterator i = dynamic_param_list_.begin(),
end = dynamic_param_list_.end();
-
+
for(; i != end; ++i)
{
- const Node::time_set &tset = i->second->get_times();
+ const Node::time_set &tset = i->second->get_times();
set.insert(tset.begin(),tset.end());
}
}
group_=x;
signal_added_to_group()(group_);
}
-
+
void
Layer::remove_from_group(const String&x)
{
if(group_==x)
remove_from_all_groups();
}
-
+
void
Layer::remove_from_all_groups()
{
signal_removed_from_group()(group_);
group_.clear();
}
-
+
String
Layer::get_group()const
{
{
friend class ValueNode;
friend class Context;
-
+
/*
-- ** -- T Y P E S -----------------------------------------------------------
*/
static void register_in_book(const BookEntry &);
static Book& book();
-
+
static bool subsys_init();
static bool subsys_stop();
//! \writeme
float z_depth_;
-
+
//! \writeme
mutable Time dirty_time_;
-
+
//! Contains the name of the group that this layer belongs to
String group_;
-
+
//! \writeme
sigc::connection parent_death_connect_;
-
+
/*
-- ** -- S I G N A L S -------------------------------------------------------
*/
private:
//! Status Changed
- sigc::signal<void> signal_status_changed_;
-
+ sigc::signal<void> signal_status_changed_;
+
//! Parameter changed
- sigc::signal<void,String> signal_param_changed_;
+ sigc::signal<void,String> signal_param_changed_;
//! Description Changed
- sigc::signal<void> signal_description_changed_;
+ sigc::signal<void> signal_description_changed_;
//! Moved
- sigc::signal<void, int, etl::handle<Canvas> > signal_moved_;
+ sigc::signal<void, int, etl::handle<Canvas> > signal_moved_;
- sigc::signal<void, String> signal_added_to_group_;
+ sigc::signal<void, String> signal_added_to_group_;
- sigc::signal<void, String> signal_removed_from_group_;
+ sigc::signal<void, String> signal_removed_from_group_;
/*
-- ** -- S I G N A L I N T E R F A C E -------------------------------------
public:
//! Status Changed
- sigc::signal<void>& signal_status_changed() { return signal_status_changed_; }
-
+ sigc::signal<void>& signal_status_changed() { return signal_status_changed_; }
+
//! Parameter changed
sigc::signal<void,String>& signal_param_changed() { return signal_param_changed_; }
//! Description Changed
- sigc::signal<void>& signal_description_changed() { return signal_description_changed_;}
+ sigc::signal<void>& signal_description_changed() { return signal_description_changed_;}
//! Moved
sigc::signal<void, int, etl::handle<Canvas> >& signal_moved() { return signal_moved_; }
- sigc::signal<void, String>& signal_added_to_group() { return signal_added_to_group_; }
+ sigc::signal<void, String>& signal_added_to_group() { return signal_added_to_group_; }
- sigc::signal<void, String>& signal_removed_from_group() { return signal_removed_from_group_; }
+ sigc::signal<void, String>& signal_removed_from_group() { return signal_removed_from_group_; }
/*
-- ** -- C O N S T R U C T O R S ---------------------------------------------
//! Adds this layer to the given layer group
void add_to_group(const String&);
-
+
//! Removes this layer from the given layer group
void remove_from_group(const String&);
-
+
//! Removes this layer from all layer groups
void remove_from_all_groups();
-
+
//! Gets the name of the group that this layer belongs to
String get_group()const;
bool connect_dynamic_param(const String& param, etl::loose_handle<ValueNode>);
bool disconnect_dynamic_param(const String& param);
-
+
//! Enables the layer for rendering (Making it \em active)
void enable() { set_active(true); }
//! \writeme
void set_z_depth(float x) { z_depth_=x; }
-
+
//! Sets the Canvas that this Layer is a part of
void set_canvas(etl::loose_handle<Canvas> canvas);
-
+
//! Returns a handle to the Canvas to which this Layer belongs
etl::loose_handle<Canvas> get_canvas()const;
-
+
//! \writeme
const String& get_description()const { return description_; }
//! \writeme
void set_description(const String& x);
-
+
/*
-- ** -- V I R T U A L F U N C T I O N S -----------------------------------
*/
virtual Rect get_full_bounding_rect(Context context)const;
//! Returns a string containing the name of the Layer
- virtual String get_name()const;
+ virtual String get_name()const;
//! Returns a string containing the localized name of the Layer
virtual String get_local_name()const;
gamma_adjust (1.0)
{
}
-
+
bool
synfig::Layer_Bitmap::set_param(const String & param, ValueBase value)
{
//gamma_adjust.set_gamma(1.0/value.get(Real()));
return true;
}
-
+
return Layer_Composite::set_param(param,value);
}
{
return surface.get_h();
}
-
+
return Layer_Composite::get_param(param);
}
Layer_Bitmap::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("tl")
.set_local_name(_("Top-Left"))
.set_description(_("Upper left-hand Corner of image"))
{
Point surface_pos;
surface_pos=pos-tl;
-
+
surface_pos[0]/=br[0]-tl[0];
if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0)
{
return const_cast<Layer_Bitmap*>(this);
}
}
-
+
return context.hit_check(pos);
}
return c;
static Color x;
x=c;
-
+
x.set_r(powf((float)x.get_r(),gamma_adjust));
x.set_g(powf((float)x.get_g(),gamma_adjust));
x.set_b(powf((float)x.get_b(),gamma_adjust));
if(!get_amount())
return context.get_color(pos);
-
+
surface_pos=pos-tl;
-
+
surface_pos[0]/=br[0]-tl[0];
if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0)
{
{
surface_pos[0]*=surface.get_w();
surface_pos[1]*=surface.get_h();
-
+
Color ret(Color::alpha());
switch(c)
}
break;
}
-
+
ret=filter(ret);
-
+
if(get_amount()==1 && get_blend_method()==Color::BLEND_STRAIGHT)
return ret;
else
return Color::blend(ret,context.get_color(pos),get_amount(),get_blend_method());
}
}
-
+
return context.get_color(pos);
}
// We can only handle NN and Linear at the moment
//if(interp>1)
// return Layer_Composite::accelerated_render(context,out_surface,quality,renddesc,cb);
-
+
//if we don't actually have a valid surface just skip us
if(!surface.is_valid())
{
// Render what is behind us
return context.accelerated_render(out_surface,quality,renddesc,cb);
}
-
+
SuperCallback subcb(cb,1,10000,10001+renddesc.get_h());
if( get_amount()==1 &&
if(!context.accelerated_render(out_surface,quality,renddesc,&subcb))
return false;
}
-
+
if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
Point obr = renddesc.get_br(),
otl = renddesc.get_tl();
-
+
//Vector::value_type pw=renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
//Vector::value_type ph=renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
-
+
//A = representation of input (just tl,br) //just a scaling right now
//B = representation of output (just tl,br) //just a scaling right now
//sa = scaling for input (0,1) -> (0,w/h)
//sb = scaling for output (0,1) -> (0,w/h)
-
+
float inwf = br[0] - tl[0];
float inhf = br[1] - tl[1];
-
+
float outwf = obr[0] - otl[0];
float outhf = obr[1] - otl[1];
-
+
int inw = surface.get_w();
int inh = surface.get_h();
-
+
int outw = renddesc.get_w();
int outh = renddesc.get_h();
-
+
//need to get the input coords in output space, so we can clip
-
+
//get the desired corners of the bitmap (in increasing order) in integers
//floating point corners
float x1f = (tl[0] - otl[0])*outw/outwf;
float x2f = (br[0] - otl[0])*outw/outwf;
float y1f = (tl[1] - otl[1])*outh/outhf;
float y2f = (br[1] - otl[1])*outh/outhf;
-
+
if(x1f > x2f) swap(x1f,x2f);
if(y1f > y2f) swap(y1f,y2f);
-
+
int x_start = max(0,(int)floor(x1f)); //probably floor
int x_end = min(outw,(int)ceil(x2f)); //probably ceil
int y_start = max(0,(int)floor(y1f)); //probably floor
int y_end = min(outh,(int)ceil(y2f)); //probably ceil
-
+
//need to get the x,y,dx,dy values from output space to input, so we can do fast interpolation
-
+
//get the starting position in input space... for interpolating
-
+
// in int -> out float:
// Sb(B^-1)A(Sa^-1) x
float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - tl[0])*inw/inwf; //may want to bias this (center of pixel)???
float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - tl[1])*inh/inhf; //may want to bias this (center of pixel)???
-
+
//calculate the delta values in input space for one pixel movement in output space
//same matrix but with a vector instead of a point...
float indx = outwf*(inw)/((outw)*inwf); //translations died
float indy = outhf*(inh)/((outh)*inhf); //translations died
-
- //perhaps use a DDA algorithm... if faster...
+
+ //perhaps use a DDA algorithm... if faster...
// will still want pixel fractions to be floating point since colors are
//synfig::info("xstart:%d ystart:%d xend:%d yend:%d",x_start,y_start,x_end,y_end);
-
+
//start drawing at the start of the bitmap (either origin or corner of input...)
//and get other info
Surface::alpha_pen pen(out_surface->get_pen(x_start,y_start));
pen.set_alpha(get_amount());
pen.set_blend_method(get_blend_method());
-
+
//check if we should use the downscale filtering
if(quality <= 7)
{
- //the stride of the value should be inverted because we want to downsample
+ //the stride of the value should be inverted because we want to downsample
//when the stride is small, not big
//int multw = (int)ceil(indx);
//int multh = (int)ceil(indy);
-
+
if(indx > 1.7 || indy > 1.7)
{
- /*synfig::info("Decided to downsample? ratios - (%f,%f) -> (%d,%d)",
- indx, indy, multw, multh); */
-
+ /*synfig::info("Decided to downsample? ratios - (%f,%f) -> (%d,%d)",
+ indx, indy, multw, multh); */
+
//use sample rect here...
-
+
float iny, inx;
int x,y;
-
+
//Point sample - truncate
iny = iny_start;//+0.5f;
for(y = y_start; y < y_end; ++y, pen.inc_y(), iny += indy)
}
pen.dec_x(x_end-x_start);
}
-
+
//Color c = (*out_surface)[0][0];
//synfig::info("ValueBase of first pixel = (%f,%f,%f,%f)",c.get_r(),c.get_g(),c.get_b(),c.get_a());
-
+
return true;
}
}
-
+
//perform normal interpolation
if(interp==0)
- {
+ {
//synfig::info("Decided to do nearest neighbor");
float iny, inx;
int x,y;
-
+
//Point sample - truncate
iny = iny_start;//+0.5f;
for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
if(interp==1)
{
//bilinear filtering
-
+
//float xmf,xpf,ymf,ypf;
//int xm,xp,ym,yp;
float inx,iny;
int x,y;
-
+
//can probably buffer for x values...
-
+
//loop and based on inx,iny sample input image
iny = iny_start;
for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
pen.put_value(filter(surface.linear_sample(inx,iny)));
}
pen.dec_x(x_end-x_start);
-
+
}
- }
+ }
else
if(interp==2)
{
//cosine filtering
-
+
//float xmf,xpf,ymf,ypf;
//int xm,xp,ym,yp;
float inx,iny;
int x,y;
-
+
//can probably buffer for x values...
-
+
//loop and based on inx,iny sample input image
iny = iny_start;
for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
pen.put_value(filter(surface.cosine_sample(inx,iny)));
}
pen.dec_x(x_end-x_start);
-
+
}
- }
+ }
else
{
//cubic filtering
-
+
//float xmf,xpf,ymf,ypf;
//int xm,xp,ym,yp;
float inx,iny;
int x,y;
-
+
//can probably buffer for x values...
-
+
//loop and based on inx,iny sample input image
iny = iny_start;
for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
pen.put_value(filter(surface.cubic_sample(inx,iny)));
}
pen.dec_x(x_end-x_start);
-
+
}
- }
+ }
return true;
}
{
const Color& filter(const Color& c)const;
public:
- typedef etl::handle<Layer_Bitmap> Handle;
+ typedef etl::handle<Layer_Bitmap> Handle;
Point tl;
Point br;
int c;
mutable Surface surface;
-
+
Real gamma_adjust;
-
+
Layer_Bitmap();
-
+
virtual bool set_param(const String & param, ValueBase value);
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
-
+
virtual Vocab get_param_vocab()const;
virtual Rect get_bounding_rect()const;
Layer_Composite::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc_, ProgressCallback *cb) const
{
RendDesc renddesc(renddesc_);
-
+
if(!amount_)
return context.accelerated_render(surface,quality,renddesc,cb);
Layer_Bitmap::Handle surfacelayer(new class Layer_Bitmap());
Context iter;
-
+
for(iter=context;*iter;iter++)
image.push_back(*iter);
// Set up a surface target
Target::Handle target(surface_target(surface));
-
+
if(!target)
{
if(cb)cb->error(_("Unable to create surface target"));
return false;
}
-
+
RendDesc desc(renddesc);
-
+
target->set_rend_desc(&desc);
// Render the scene
Layer_Composite& set_blend_method(Color::BlendMethod x) { blend_method_=x; return *this; }
bool is_solid_color()const { return amount_==1.0f && blend_method_==Color::BLEND_STRAIGHT; }
-
+
bool is_disabled()const { return amount_==0.0f; }
-
+
virtual Vocab get_param_vocab()const;
virtual bool set_param(const String ¶m, const ValueBase &value);
if(iter->first!="Version")
ret.push_back(ParamDesc(iter->first));
}
-
+
// ... and return it
return ret;
}
aperture (0)
{
}
-
+
bool
Layer_MotionBlur::set_param(const String ¶m, const ValueBase &value)
{
- IMPORT(aperture);
+ IMPORT(aperture);
return Layer_Composite::set_param(param,value);
}
Layer_MotionBlur::get_param(const String ¶m)const
{
EXPORT(aperture);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
+
return Layer_Composite::get_param(param);
}
Time time(time_cur);
time+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) *aperture -aperture*0.5;
context.set_time(time, pos);
- }
+ }
*/
return context.get_color(pos);
}
{
Layer::Vocab ret;
//ret=Layer_Composite::get_param_vocab();
-
+
ret.push_back(ParamDesc("aperture")
.set_local_name(_("Aperture"))
.set_description(_("Shutter Time"))
);
-
+
return ret;
}
samples=3;
break;
case 10: // Rough Quality
- default:
+ default:
samples=1;
break;
-
+
}
-
+
Surface tmp;
int i;
surface->set_wh(renddesc.get_w(),renddesc.get_h());
surface->clear();
-
+
for(i=0;i<samples;i++)
{
subimagecb=SuperCallback(cb,i*(5000/samples),(i+1)*(5000/samples),5000);
}
else
return context.accelerated_render(surface,quality,renddesc,cb);
-
+
return true;
}
/* === S T R U C T S & C L A S S E S ======================================= */
namespace synfig {
-
+
class Layer_MotionBlur : public synfig::Layer_Composite
{
SYNFIG_LAYER_MODULE_EXT
public:
Layer_MotionBlur();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
-
+
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual void set_time(Context context, Time time)const;
virtual void set_time(Context context, Time time, const Point &pos)const;
-
+
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
virtual Vocab get_param_vocab()const;
*/
//if(canvas)DEBUGINFO(strprintf("%d",canvas->count()));
-
+
set_sub_canvas(0);
//if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root()))
if(!canvas) return _("Pasted Canvas");
if(canvas->is_inline()) return _("Inline Canvas");
if(canvas->get_root()==get_canvas()->get_root()) return '[' + canvas->get_id() + ']';
-
+
return '[' + canvas->get_file_name() + ']';
}
Layer_PasteCanvas::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("origin")
.set_local_name(_("Origin"))
.set_description(_("Point where you want the origin to be"))
ret.push_back(ParamDesc("children_lock")
.set_local_name(_("Children Lock"))
);
-
+
return ret;
}
Layer_PasteCanvas::set_param(const String & param, const ValueBase &value)
{
IMPORT(origin);
-
+
if(param=="canvas" && value.same_as(Canvas::Handle()))
{
set_sub_canvas(value.get(Canvas::Handle()));
IMPORT(children_lock);
IMPORT(zoom);
IMPORT(time_offset);
-
+
return Layer_Composite::set_param(param,value);
}
{
if(canvas && !do_not_muck_with_time_)
remove_child(canvas.get());
-
+
if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root()))
canvas->unref();
-
+
child_changed_connection.disconnect();
-
+
canvas=x;
-
+
/*if(canvas)
child_changed_connection=canvas->signal_changed().connect(
sigc::mem_fun(
*/
if(canvas)
bounds=(canvas->get_context().get_full_bounding_rect()-canvas->rend_desc().get_focus())*exp(zoom)+origin+canvas->rend_desc().get_focus();
-
+
if(canvas && !do_not_muck_with_time_)
add_child(canvas.get());
if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root()))
canvas->ref();
-
+
if(canvas)
on_canvas_set();
}
EXPORT(zoom);
EXPORT(time_offset);
EXPORT(children_lock);
-
+
EXPORT_NAME();
EXPORT_VERSION();
{
if(depth==MAX_DEPTH)return;depth_counter counter(depth);
curr_time=time;
-
+
context.set_time(time);
if(canvas)
{
canvas->set_time(time);
-
+
bounds=(canvas->get_context().get_full_bounding_rect()-canvas->rend_desc().get_focus())*exp(zoom)+origin+canvas->rend_desc().get_focus();
}
else
if(depth==MAX_DEPTH)return Color::alpha();depth_counter counter(depth);
Point target_pos=(pos-canvas->rend_desc().get_focus()-origin)/exp(zoom)+canvas->rend_desc().get_focus();
-
+
return Color::blend(canvas->get_context().get_color(target_pos),context.get_color(pos),get_amount(),get_blend_method());
}
return context.accelerated_render(surface,quality,renddesc,cb);
}
depth_counter counter(depth);
-
+
if(!canvas || !get_amount())
return context.accelerated_render(surface,quality,renddesc,cb);
-
+
if(!do_not_muck_with_time_ && curr_time!=Time::begin() && canvas->get_time()!=curr_time+time_offset)
{
canvas->set_time(curr_time+time_offset);
}
-
+
SuperCallback stageone(cb,0,4500,10000);
SuperCallback stagetwo(cb,4500,9000,10000);
SuperCallback stagethree(cb,9000,9999,10000);
else if(!context.accelerated_render(surface,quality,renddesc,&stageone))
return false;
Color::BlendMethod blend_method(get_blend_method());
-
+
const Rect full_bounding_rect(canvas->get_context().get_full_bounding_rect());
if(context->empty())
{
if(Color::is_onto(blend_method))
return true;
-
+
if(blend_method==Color::BLEND_COMPOSITE)
blend_method=Color::BLEND_STRAIGHT;
}
{
if(Color::is_onto(blend_method))
return true;
-
+
if(blend_method==Color::BLEND_COMPOSITE)
blend_method=Color::BLEND_STRAIGHT;
}
-
+
#ifndef SYNFIG_NO_CLIP
{
//synfig::info("PasteCanv Clip");
Rect area(desc.get_rect()&full_bounding_rect);
-
+
Point min(area.get_min());
Point max(area.get_max());
if(desc.get_tl()[1]>desc.get_br()[1])
swap(min[1],max[1]);
- const int
+ const int
x(floor_to_int((min[0]-desc.get_tl()[0])/desc.get_pw())),
y(floor_to_int((min[1]-desc.get_tl()[1])/desc.get_ph())),
w(ceil_to_int((max[0]-desc.get_tl()[0])/desc.get_pw())-x),
h(ceil_to_int((max[1]-desc.get_tl()[1])/desc.get_ph())-y);
-
+
desc.set_subwindow(x,y,w,h);
-
+
Surface pastesurface;
-
+
if(area.area()<=0.000001 || desc.get_w()==0 || desc.get_h()==0)
{
if(cb && !cb->amount_complete(10000,10000)) return false;
if(!canvas->get_context().accelerated_render(&pastesurface,quality,desc,&stagetwo))
return false;
-
+
Surface::alpha_pen apen(surface->get_pen(x,y));
-
+
apen.set_alpha(get_amount());
apen.set_blend_method(blend_method);
-
+
pastesurface.blit_to(apen);
}
#else
{
Surface pastesurface;
-
+
if(!canvas->get_context().accelerated_render(&pastesurface,quality,desc,&stagetwo))
return false;
-
+
Surface::alpha_pen apen(surface->begin());
-
+
apen.set_alpha(get_amount());
apen.set_blend_method(blend_method);
-
+
pastesurface.blit_to(apen);
}
#endif
-
+
if(cb && !cb->amount_complete(10000,10000)) return false;
return true;
if(canvas) tset = canvas->get_times();
Node::time_set::iterator i = tset.begin(),
- end = tset.end();
-
+ end = tset.end();
+
//Make sure we offset the time...
- //TODO: SOMETHING STILL HAS TO BE DONE WITH THE OTHER DIRECTION
+ //TODO: SOMETHING STILL HAS TO BE DONE WITH THE OTHER DIRECTION
// (recursing down the tree needs to take this into account too...)
for(; i != end; ++i)
{
set.insert(*i + time_offset);
}
-
+
Layer::get_times_vfunc(set);
}
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
class Layer_PasteCanvas : public Layer_Composite, public Layer_NoDeform
{
SYNFIG_LAYER_MODULE_EXT
bool optimize_layers(synfig::Context context,synfig::CanvasBase&)const;
bool do_not_muck_with_time_;
-
+
bool children_lock;
mutable Rect bounds;
etl::handle<synfig::Canvas> get_sub_canvas()const { return canvas; }
void set_sub_canvas(etl::handle<synfig::Canvas> x);
-
+
Real get_zoom()const { return zoom; }
Time get_time_offset()const { return time_offset; }
virtual ~Layer_PasteCanvas();
virtual String get_local_name()const;
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual synfig::Rect get_bounding_rect()const;
virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
-
+
protected:
- virtual void get_times_vfunc(Node::time_set &set) const;
+ virtual void get_times_vfunc(Node::time_set &set) const;
}; // END of class Layer_PasteCanvas
// Build edge table
move_to(vector_list[0][0],vector_list[0][1]);
-
+
for(i = 1;i < pointcount; i++)
{
if(isnan(vector_list[i][0]) || isnan(vector_list[i][1]))
// Build edge table
move_to(point_list[0][0],point_list[0][1]);
-
+
for(i = 1;i < pointcount; i++)
{
if(isnan(point_list[i][0]) || isnan(point_list[i][1]))
Layer_Shape::clear();
vector_list.clear();
}
-
+
bool
Layer_Polygon::set_param(const String & param, const ValueBase &value)
{
sync();
return true;
}
-
+
return Layer_Shape::set_param(param,value);
}
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Shape::get_param(param);
+
+ return Layer_Shape::get_param(param);
}
Layer::Vocab
Layer_Polygon::get_param_vocab()const
{
Layer::Vocab ret(Layer_Shape::get_param_vocab());
-
+
ret.push_back(ParamDesc("vector_list")
.set_local_name(_("Vector List"))
.set_origin("offset")
);
-
+
return ret;
}
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
/*! \class Layer_Polygon
** \beief writeme
** \todo This layer needs to support multiple polygons */
class Layer_Polygon : public Layer_Shape
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
-
+
//exported data
std::vector< Point > vector_list;
//! Updates EdgeTable so it will reflect the parameter data
void sync();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
-
+
virtual Vocab get_param_vocab()const;
private:
{
int operation;
int number;
-
+
//Point data[0];
-
+
enum Operations
{
NONE = -1,
static void Subd_Conic_Stack(Point *arc)
{
/*
-
+
b0
* 0+1 a
b1 b * 1+2*1+2 a
* 1+2 b *
- b2 *
- *
-
+ b2 *
+ *
+
0.1.2 -> 0.1 2 3.4
-
+
*/
-
+
Real a,b;
-
-
+
+
arc[4][0] = arc[2][0];
- b = arc[1][0];
-
+ b = arc[1][0];
+
a = arc[1][0] = (arc[0][0] + b)/2;
- b = arc[3][0] = (arc[4][0] + b)/2;
+ b = arc[3][0] = (arc[4][0] + b)/2;
arc[2][0] = (a + b)/2;
-
-
+
+
arc[4][1] = arc[2][1];
b = arc[1][1];
-
+
a = arc[1][1] = (arc[0][1] + b)/2;
b = arc[3][1] = (arc[4][1] + b)/2;
arc[2][1] = (a + b)/2;
-
+
/* //USING SIMD
-
+
arc[4] = arc[2];
-
+
arc[3] = (arc[2] + arc[1])/2;
arc[1] = (arc[0] + arc[1])/2;
arc[2] = (arc[1] + arc[3])/2;
-
+
*/
-
+
}
static void Subd_Cubic_Stack(Point *arc)
{
Real a,b,c;
-
+
/*
-
+
b0
* 0+1 a
b1 b * 1+2*1+2 a
b2 c * 1+2*2+2 b *
* 2+3 c *
b3 *
- *
-
+ *
+
0.1 2.3 -> 0.1 2 3 4 5.6
-
+
*/
-
+
arc[6][0] = arc[3][0];
-
+
b = arc[1][0];
c = arc[2][0];
-
+
a = arc[1][0] = (arc[0][0] + b)/2;
b = (b + c)/2;
c = arc[5][0] = (arc[6][0] + c)/2;
-
+
a = arc[2][0] = (a + b)/2;
b = arc[4][0] = (b + c)/2;
-
+
arc[3][0] = (a + b)/2;
-
-
+
+
arc[6][1] = arc[3][1];
-
+
b = arc[1][1];
c = arc[2][1];
-
+
a = arc[1][1] = (arc[0][1] + b)/2;
b = (b + c)/2;
c = arc[5][1] = (arc[6][1] + c)/2;
-
+
a = arc[2][1] = (a + b)/2;
b = arc[4][1] = (b + c)/2;
-
+
arc[3][1] = (a + b)/2;
-
+
/* //USING SIMD
temp
-
+
arc[6] = arc[3];
-
+
//backwards to avoid overwriting
arc[5] = (arc[2] + arc[3])/2;
temp = (arc[1] + arc[2])/2;
arc[1] = (arc[0] + arc[1])/2;
-
+
arc[4] = (temp + arc[5])/2;
arc[2] = (arc[1] + temp)/2;
-
+
arc[3] = (arc[2] + arc[4])/2;
-
+
*/
}
Rect aabb;
int ydir;
vector<Point> pointlist;
-
+
MonoSegment(int dir = 0, Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
- {
+ {
aabb.minx = x0;
aabb.maxx = x1;
aabb.miny = y0;
ydir = dir;
}
-
+
int intersect(Real x,Real y) const
{
if((y < aabb.miny) | (y > aabb.maxy) | (x < aabb.minx)) return 0;
if(x > aabb.maxx) return ydir;
-
+
//int i = 0;
//int size = pointlist.size();
//vector<Point>::const_iterator end = pointlist.end();
vector<Point>::const_iterator p = pointlist.begin();
-
+
//assumes that the rect culled away anything that would be beyond the edges
if(ydir > 0)
{
{
while(y < (*++p)[1]);
}
-
+
//for the loop to break there must have been a slope (straight line would do nothing)
//vector<Point>::const_iterator p1 = p-1;
Real dy = p[-1][1] - p[0][1];
Real dx = p[-1][0] - p[0][0];
-
+
assert(dy != 0);
-
+
Real xi = p[0][0] + (y - p[0][1]) * dx / dy;
return (x > xi)*ydir;
}
Rect aabb; //not necessarily as effective - can only reject values
vector<Point> pointlist; //run length - p0, p1, p2, p3 = p10, p11, p12, p13 = p20 ...
vector<char> degrees;
-
+
CurveArray(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
- {
+ {
aabb.set(x0,y0,x1,y1);
}
-
+
void reset(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0)
{
aabb.set(x0,y0,x1,y1);
pointlist.clear();
degrees.clear();
}
-
+
int size () const
{
return degrees.size();
}
-
+
void Start(Point m)
- {
+ {
reset(m[0],m[0],m[1],m[1]);
- pointlist.push_back(m);
+ pointlist.push_back(m);
}
-
+
void AddCubic(Point p1, Point p2, Point dest)
{
aabb.expand(p1[0],p1[1]);
aabb.expand(p2[0],p2[1]);
aabb.expand(dest[0],dest[1]);
-
+
pointlist.push_back(p1);
pointlist.push_back(p2);
pointlist.push_back(dest);
-
+
degrees.push_back(3);
}
-
+
void AddConic(Point p1, Point dest)
{
aabb.expand(p1[0],p1[1]);
aabb.expand(dest[0],dest[1]);
-
+
pointlist.push_back(p1);
pointlist.push_back(dest);
-
+
degrees.push_back(2);
}
-
+
static int intersect_conic(Real x, Real y, Point *p, int level = 0)
{
Real ymin,ymax,xmin,xmax;
int intersects = 0;
-
+
//sort the overall curve ys - degenerate detection
ymin = min(p[0][1],p[2][1]);
ymax = max(p[0][1],p[2][1]);
-
+
xmin = min(min(p[0][0],p[1][0]),p[2][0]);
xmax = max(max(p[0][0],p[1][0]),p[2][0]);
-
+
//to the left, to the right and out of range y, or completely out of range y
if( x < xmin ) return 0;
if( x > xmax & (y > ymax | y < ymin) ) return 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])
return 0;
-
+
//degenerate accept - to the right and crossing the base line
if(x > xmax)
{
}
//solve for curve = y
-
- //real roots:
+
+ //real roots:
//0 roots - 0 intersection
//1 root - get x, and figure out x
//2 roots (non-double root) - get 2 xs, and count xs to the left
-
+
//for conic we can assume 1 intersection for monotonic curve
Real a = p[2][1] - 2*p[1][1] + p[0][1],
b = 2*p[1][1] - 2*p[0][1],
c = p[0][1] - y;
-
+
Real t1 = -1, t2 = -1;
-
+
if(a == 0)
{
//linear - easier :)
if(b == 0) return 0; //may not need this check
-
+
t1 = - c / b; //bt + c = 0 solved
}else
{
//2 degree polynomial
Real b2_4ac = b*b - 4*a*c;
-
+
//if there are double/no roots - no intersections (in real #s that is)
if(b2_4ac <= 0)
{
return 0;
}
-
+
b2_4ac = sqrt(b2_4ac);
-
+
t1 = (-b - b2_4ac) / 2*a,
t2 = (-b + b2_4ac) / 2*a;
}
-
- //calculate number of intersections
+
+ //calculate number of intersections
if(t1 >= 0 & t1 <= 1)
{
const Real t = t1;
const Real invt = 1 - t;
-
+
//find x val and it counts if it's to the left of the point
const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0];
const Real dy_t = 2*a*t + b;
-
+
if(dy_t)
{
intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
{
const Real t = t2;
const Real invt = 1 - t;
-
+
//find x val and it counts if it's to the left of the point
const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0];
const Real dy_t = 2*a*t + b;
-
+
if(dy_t)
{
intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1);
}
}
-
+
return intersects;
}
-
+
static int quadratic_eqn(Real a, Real b, Real c, Real *t0, Real *t1)
{
const Real b2_4ac = b*b - 4*a*c;
-
+
//degenerate reject (can't take sqrt)
if(b2_4ac < 0)
{
return 0;
}
-
- const Real sqrtb2_4ac = sqrt(b2_4ac);
+
+ const Real sqrtb2_4ac = sqrt(b2_4ac);
const Real signb = b < 0 ? -1 : 1;
const Real q = - 0.5 * (b + signb * sqrtb2_4ac);
-
+
*t0 = q/a;
*t1 = c/q;
-
+
return sqrtb2_4ac == 0 ? 1 : 2;
}
-
+
//Newton-Raphson root polishing (we don't care about bounds, assumes very near the desired root)
static Real polish_cubicroot(Real a, Real b, Real c, Real d, Real t, Real *dpdt)
{
const Real cn[4] = {a,b,c,d};
Real p,dp,newt,oldpmag=FLT_MAX;
-
+
//eval cubic eqn and it's derivative
for(;;)
{
p = cn[0]*t + cn[1];
dp = cn[0];
-
+
for(int i = 2; i < 4; i++)
{
dp = p + dp*t;
p = cn[i] + p*t;
}
-
+
if(dp == 0)
{
synfig::warning("polish_cubicroot: Derivative should not vanish!!!");
*dpdt = dp;
return t;
}
-
- t = newt;
+
+ t = newt;
oldpmag = fabs(p);
}
}
-
+
static int intersect_cubic(Real x, Real y, Point *p, int level = 0)
{
const Real INVALIDROOT = -FLT_MAX;
Real ymin,ymax,xmin,xmax;
Real ymin2,ymax2,ymintot,ymaxtot;
int intersects = 0;
-
+
//sort the overall curve ys and xs - degenerate detection
-
+
//open span for the two end points
ymin = min(p[0][1],p[3][1]);
ymax = max(p[0][1],p[3][1]);
-
+
//other points etc.
ymin2 = min(p[1][1],p[2][1]);
ymax2 = max(p[1][1],p[2][1]);
-
+
ymintot = min(ymin,ymin2);
ymaxtot = max(ymax,ymax2);
-
+
//the entire curve control polygon is in this x range
xmin = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0]));
xmax = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][0]));
-
+
//outside all y boundaries (no intersect)
if( (y > ymaxtot) || (y < ymintot) ) return 0;
-
+
//left of curve (no intersect)
if(x < xmin) return 0;
-
+
//right of curve (and outside base range)
if( x > xmax )
{
if( (y > ymax) | (y < ymin) ) return 0;
-
+
//degenerate accept - to the right and inside the [ymin,ymax] range (already rejected if out of range)
const Real n = p[3][1] - p[0][1];
-
+
//extract the sign from the value (we need valid data)
return n < 0 ? -1 : 1;
}
-
+
//degenerate horizontal line max -- doesn't happen enough to check for
if( ymintot == ymaxtot ) return 0;
-
+
//calculate roots:
// can have 0,1,2, or 3 real roots
// if any of them are double then reject the two...
-
+
// y-coefficients for f_y(t) - y = 0
Real a = p[3][1] - 3*p[2][1] + 3*p[1][1] - p[0][1],
b = 3*p[2][1] - 6*p[1][1] + 3*p[0][1],
c = 3*p[1][1] - 3*p[0][1],
d = p[0][1] - y;
-
+
Real ax = p[3][0] - 3*p[2][0] + 3*p[1][0] - p[0][0],
bx = 3*p[2][0] - 6*p[1][0] + 3*p[0][0],
cx = 3*p[1][0] - 3*p[0][0],
dx = p[0][0];
-
+
Real t1 = INVALIDROOT, t2 = INVALIDROOT, t3 = INVALIDROOT, t, dydt;
-
+
if(a == 0)
{
//only 2nd degree
{
//linear
if(c == 0) return 0;
-
+
t1 = - d / c; //equation devolved into: ct + d = 0 - solve...
}else
{
//0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective)
if(quadratic_eqn(a,b,c,&t1,&t2) != 2) return 0;
- }
+ }
}else
{
//cubic - sigh....
-
+
//algorithm courtesy of Numerical Recipes in C (algorithm copied from pg. 184/185)
Real an = b / a,
bn = c / a,
cn = d / a;
-
+
//if cn is 0 (or really really close), then we can simplify this...
if(IsZero(cn))
{
}
}
else
- {
+ {
//otherwise run the normal cubic root equation
Real Q = (an*an - 3.0*bn) / 9.0;
Real R = ((2.0*an*an - 9.0*bn)*an + 27.0*cn)/54.0;
-
+
if(R*R < Q*Q*Q)
{
Real theta = acos(R / sqrt(Q*Q*Q));
-
+
t1 = -2.0*sqrt(Q)*cos(theta/3) - an/3.0;
t2 = -2.0*sqrt(Q)*cos((theta+2*PI)/3.0) - an/3.0;
t3 = -2.0*sqrt(Q)*cos((theta-2*PI)/3.0) - an/3.0;
-
+
//don't need to reorder,l just need to eliminate double/triple roots
//if(t3 == t2 & t1 == t2) t2 = t3 = INVALIDROOT;
if(t3 == t2) t2 = t3 = INVALIDROOT;
{
Real signR = R < 0 ? -1 : 1;
Real A = - signR * pow(signR*R + sqrt(R*R - Q*Q*Q),1/3.0);
-
+
Real B;
if(A == 0) B = 0;
else B = Q / A;
-
+
//single real root in this case
t1 = (A + B) - an/3.0;
}
}
}
-
+
//if(t1 != INVALIDROOT)
{
t = t1;//polish_cubicroot(a,b,c,d,t1,&dydt);
if(t >= 0 & t < 1)
{
//const Real invt = 1 - t;
-
+
//find x val and it counts if it's to the left of the point
const Real xi = ((ax*t + bx)*t + cx)*t + dx;
dydt = (3*a*t + 2*b)*t + c;
-
+
if(dydt)
{
intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
if(t >= 0 & t < 1)
{
//const Real invt = 1 - t;
-
+
//find x val and it counts if it's to the left of the point
const Real xi = ((ax*t + bx)*t + cx)*t + dx;
dydt = (3*a*t + 2*b)*t + c;
-
+
if(dydt)
{
intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
if(t >= 0 & t < 1)
{
//const Real invt = 1 - t;
-
+
//find x val and it counts if it's to the left of the point
const Real xi = ((ax*t + bx)*t + cx)*t + dx;
dydt = (3*a*t + 2*b)*t + c;
-
+
if(dydt)
{
intersects += (x >= xi) * ( dydt > 0 ? 1 : -1);
}
}
}
-
+
return intersects;
}
-
+
int intersect(Real x,Real y, Point *table) const
- {
+ {
if((y < aabb.miny) | (y > aabb.maxy) | (x < aabb.minx)) return 0;
-
+
int i, curdeg, intersects = 0;
const int numcurves = degrees.size();
-
+
vector<Point>::const_iterator p = pointlist.begin();
-
+
for(i=0; i < numcurves; i++)
{
curdeg = degrees[i];
-
+
switch(curdeg)
{
case 2:
table[0] = *p++;
table[1] = *p++;
table[2] = *p; //we want to include the last point for the next curve
-
+
intersects += intersect_conic(x,y,table);
-
+
break;
}
-
+
case 3:
{
table[0] = *p++;
table[1] = *p++;
table[2] = *p++;
table[3] = *p; //we want to include the last point for the next curve
-
+
intersects += intersect_cubic(x,y,table);
-
+
break;
}
-
+
default:
{
warning("Invalid degree (%d) inserted into the list (index: %d)\n", curdeg, i);
return 0;
}
- }
+ }
}
-
+
return intersects;
}
};
struct Layer_Shape::Intersector
-{
+{
Rect aabb;
bool initaabb;
-
+
int flags;
-
+
enum IntersectorFlags
{
NotClosed = 0x8000
};
-
+
enum PrimitiveType
{
TYPE_NONE = 0,
TYPE_LINE,
TYPE_CURVE
};
-
+
Real cur_x,cur_y;
Real close_x,close_y;
-
- vector<MonoSegment> segs; //monotonically increasing
+
+ vector<MonoSegment> segs; //monotonically increasing
vector<CurveArray> curves; //big array of consecutive curves
-
+
int prim;
Vector tangent;
-
+
Intersector()
{
clear();
}
-
+
bool notclosed()
{
return (flags & NotClosed) | (cur_x != close_x) | (cur_y != close_y);
}
-
+
void move_to(Real x, Real y)
{
close();
-
+
close_x = cur_x = x;
close_y = cur_y = y;
-
+
tangent[0] = tangent[1] = 0;
-
- if(initaabb)
+
+ if(initaabb)
{
aabb.set_point(x,y);
initaabb = false;
}else aabb.expand(x,y);
-
+
prim = TYPE_NONE;
}
-
+
void line_to(Real x, Real y)
{
int dir = (y > cur_y)*1 + (-1)*(y < cur_y);
-
+
//check for context (if not line start a new segment)
//if we're not in line mode (cover's 0 set case), or if directions are different (not valid for 0 direction)
if(prim != TYPE_LINE || (dir && segs.back().ydir != dir))
{
MonoSegment seg(dir,x,x,y,y);
-
+
seg.aabb.expand(cur_x,cur_y);
seg.pointlist.push_back(Point(cur_x,cur_y));
seg.pointlist.push_back(Point(x,y));
}
//add to the last segment, because it works
else
- {
+ {
segs.back().pointlist.push_back(Point(x,y));
segs.back().aabb.expand(x,y);
}
-
+
cur_x = x;
cur_y = y;
aabb.expand(x,y); //expand the entire things bounding box
-
+
tangent[0] = x - cur_x;
tangent[1] = x - cur_y;
-
+
flags |= NotClosed;
prim = TYPE_LINE;
}
-
+
void conic_to_smooth(Real x, Real y)
{
const Real x1 = tangent[0]/2.0 + cur_x;
const Real y1 = tangent[1]/2.0 + cur_y;
-
+
conic_to(x1,y1,x,y);
}
-
+
void conic_to(Real x1, Real y1, Real x, Real y)
{
//if we're not already a curve start one
c.Start(Point(cur_x,cur_y));
c.AddConic(Point(x1,y1),Point(x,y));
-
+
curves.push_back(c);
}else
{
curves.back().AddConic(Point(x1,y1),Point(x,y));
}
-
+
cur_x = x;
cur_y = y;
-
+
aabb.expand(x1,y1);
aabb.expand(x,y);
-
+
tangent[0] = 2*(x - x1);
tangent[1] = 2*(y - y1);
-
+
flags |= NotClosed;
prim = TYPE_CURVE;
}
-
+
void curve_to_smooth(Real x2, Real y2, Real x, Real y)
{
Real x1 = tangent[0]/3.0 + cur_x;
Real y1 = tangent[1]/3.0 + cur_y;
-
- curve_to(x1,y1,x2,y2,x,y);
+
+ curve_to(x1,y1,x2,y2,x,y);
}
-
+
void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y)
{
//if we're not already a curve start one
c.Start(Point(cur_x,cur_y));
c.AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
-
+
curves.push_back(c);
}else
{
curves.back().AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y));
}
-
+
cur_x = x;
cur_y = y;
-
+
//expand bounding box around ALL of it
aabb.expand(x1,y1);
aabb.expand(x2,y2);
aabb.expand(x,y);
-
+
tangent[0] = 3*(x - x2);
tangent[1] = 3*(y - y2);
-
+
flags |= NotClosed;
prim = TYPE_CURVE;
}
-
+
void close()
{
if(flags & NotClosed)
{
line_to(close_x,close_y);
}
-
+
flags &= ~NotClosed;
}
}
-
+
//assumes the line to count the intersections with is (-1,0)
int intersect (Real x, Real y) const
{
int inter = 0;
unsigned int i;
vector<MonoSegment>::const_iterator s = segs.begin();
- vector<CurveArray>::const_iterator c = curves.begin();
-
+ vector<CurveArray>::const_iterator c = curves.begin();
+
Point memory[3*MAX_SUBDIVISION_SIZE + 1];
-
+
for(i = 0; i < segs.size(); i++,s++)
{
inter += s->intersect(x,y);
}
-
+
for(i=0; i < curves.size(); i++,c++)
inter += c->intersect(x,y,memory);
-
+
return inter;
}
-
+
//intersect an arbitrary line
//int intersect (Real x, Real y, Real vx, Real vy) {return 0;}
-
+
void clear()
- {
+ {
segs.clear();
curves.clear();
-
+
flags = 0;
cur_x = cur_y = close_x = close_y = 0;
prim = TYPE_NONE;
{
int y,x;
Real cover,area;
-
- PenMark(){}
+
+ PenMark(){}
PenMark(int xin, int yin, Real c, Real a)
:y(yin),x(xin),cover(c),area(a) {}
-
+
void set(int xin, int yin, Real c, Real a) { y = yin; x = xin; cover = c; area = a; }
-
+
void setcoord(int xin, int yin) { y = yin; x = xin; }
-
+
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
{
return y == rhs.y ? x < rhs.x : y < rhs.y;
//starting position of current primitive list
Real close_x;
Real close_y;
-
+
//flags for the current segment
int flags;
NotSorted = 0x8000,
NotClosed = 0x4000
};
-
+
//default constructor - 0 everything
PolySpan() :current(0,0,0,0),flags(NotSorted)
{
cur_x = cur_y = close_x = close_y = 0;
open_index = 0;
}
-
+
bool notclosed() const
{
return (flags & NotClosed) | (cur_x != close_x) | (cur_y != close_y);
}
-
- //0 out all the variables involved in processing
+
+ //0 out all the variables involved in processing
void clear()
{
covers.clear();
cur_x = cur_y = close_x = close_y = 0;
- open_index = 0;
+ open_index = 0;
current.set(0,0,0,0);
flags = NotSorted;
}
- //add the current cell, but only if there is information to add
+ //add the current cell, but only if there is information to add
void addcurrent()
{
if(current.cover || current.area)
covers.push_back(current);
}
}
-
+
//move to the next cell (cover values 0 initially), keeping the current if necessary
void move_pen(int x, int y)
{
current.set(x,y,0,0);
}
}
-
+
//close the primitives with a line (or rendering will not work as expected)
void close()
{
flags &= ~NotClosed;
}
}
-
+
// Not recommended - destroys any separation of spans currently held
void merge_all()
{
sort(covers.begin(),covers.end());
open_index = 0;
}
-
+
//will sort the marks if they are not sorted
void sort_marks()
{
if(flags & NotSorted)
{
- //only sort the open index
+ //only sort the open index
addcurrent();
current.setcover(0,0);
-
+
sort(covers.begin() + open_index,covers.end());
flags &= ~NotSorted;
}
}
-
+
//encapsulate the current sublist of marks (used for drawing)
void encapsulate_current()
{
sort_marks();
open_index = covers.size();
}
-
+
//move to start a new primitive list (enclose the last primitive if need be)
void move_to(Real x, Real y)
{
void line_to(Real x, Real y);
void conic_to(Real x1, Real y1, Real x, Real y);
void cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real 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)
{
//non-zero winding style
if(area < 0) area = -area;
if(area > 1) area = 1;
-
+
//even-odd winding style
/*if(area < 0) area = -area;
-
+
while(area > 2) area -= 2;
if(area > 1) area = 1-area; //want pyramid like thing
*/
//broken? - yep broken
-
+
return area;
}
};
edge_table->clear();
bytestream.clear();
}
-
+
bool
Layer_Shape::set_param(const String & param, const ValueBase &value)
{
IMPORT(antialias);
IMPORT(feather);
IMPORT(blurtype);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT(antialias);
EXPORT(feather);
EXPORT(blurtype);
-
+
EXPORT_NAME();
EXPORT_VERSION();
-
+
return Layer_Composite::get_param(param);
}
Layer_Shape::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
.set_description(_("Layer_Shape Color"))
);
ret.push_back(ParamDesc("antialias")
.set_local_name(_("Antialiasing"))
- );
+ );
ret.push_back(ParamDesc("feather")
.set_local_name(_("Feather"))
.set_is_distance()
.add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur"))
.add_enum_value(Blur::DISC,"disc",_("Disc Blur"))
);
-
+
return ret;
}
Layer_Shape::hit_check(synfig::Context context, const synfig::Point &p)const
{
Point pos(p-offset);
-
+
int intercepts = edge_table->intersect(pos[0],pos[1]);
// If we have an odd number of intercepts, we are inside.
Layer_Shape::get_color(Context context, const Point &p)const
{
Point pp = p;
-
+
if(feather)
pp = Blur(feather,feather,blurtype)(p);
-
+
Point pos(pp-offset);
-
+
int intercepts = edge_table->intersect(pos[0],pos[1]);
// If we have an odd number of intercepts, we are inside.
// If we have an even number of intercepts, we are outside.
bool intersect = ((!!intercepts) ^ invert);
-
+
if(!intersect)
return context.get_color(pp);
}
//************** SCANLINE RENDERING *********************
-void Layer_Shape::PolySpan::line_to(Real x, Real y)
-{
+void Layer_Shape::PolySpan::line_to(Real x, Real y)
+{
Real n[4];
bool afterx = false;
-
+
const Real xin(x), yin(y);
-
+
Real dx = x - cur_x;
Real dy = y - cur_y;
-
+
//CLIP IT!!!!
try {
//outside y - ignore entirely
|(cur_y < window.miny & y < window.miny) )
{
cur_x = x;
- cur_y = y;
+ cur_y = y;
}
else //not degenerate - more complicated
{
if(dy > 0) //be sure it's not tooooo small
- {
+ {
// cur_y ... window.miny ... window.maxy ... y
-
+
//initial degenerate - initial clip
if(cur_y < window.miny)
{
//new clipped start point (must also move pen)
n[2] = cur_x + (window.miny - cur_y) * dx / dy;
-
+
cur_x = n[2];
cur_y = window.miny;
move_pen((int)floor(cur_x),window.miny);
}
-
- //generate data for the ending clipped info
+
+ //generate data for the ending clipped info
if(y > window.maxy)
{
//intial line to intersection (and degenerate)
n[2] = x + (window.maxy - y) * dx / dy;
-
+
//intersect coords
x = n[2];
y = window.maxy;
{
//initial degenerate - initial clip
if(cur_y > window.maxy)
- {
+ {
//new clipped start point (must also move pen)
n[2] = cur_x + (window.maxy - cur_y) * dx / dy;
-
+
cur_x = n[2];
cur_y = window.maxy;
move_pen((int)floor(cur_x),window.maxy);
}
-
- //generate data for the ending clipped info
+
+ //generate data for the ending clipped info
if(y < window.miny)
{
//intial line to intersection (and degenerate)
n[2] = x + (window.miny - y) * dx / dy;
-
+
//intersect coords
x = n[2];
y = window.miny;
}
}
-
+
//all degenerate - but require bounded clipped values
if( (cur_x >= window.maxx && x >= window.maxx)
||(cur_x < window.minx && x < window.minx) )
//clip both vertices - but only needed in the x direction
cur_x = max(cur_x, (Real)window.minx);
cur_x = min(cur_x, (Real)window.maxx);
-
- //clip the dest values - y is already clipped
+
+ //clip the dest values - y is already clipped
x = max(x,(Real)window.minx);
x = min(x,(Real)window.maxx);
-
+
//must start at new point...
move_pen((int)floor(cur_x),(int)floor(cur_y));
-
+
draw_line(cur_x,cur_y,x,y);
-
+
cur_x = xin;
cur_y = yin;
- }
+ }
else
{
//clip x
{
//need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
n[2] = cur_y + (window.minx - cur_x) * dy / dx;
-
+
move_pen(window.minx,(int)floor(cur_y));
draw_line(window.minx,cur_y,window.minx,n[2]);
-
+
cur_x = window.minx;
cur_y = n[2];
}
-
- //generate data for the ending clipped info
+
+ //generate data for the ending clipped info
if(x > window.maxx)
{
//intial line to intersection (and degenerate)
n[2] = y + (window.maxx - x) * dy / dx;
-
+
n[0] = window.maxx;
n[1] = y;
-
+
//intersect coords
x = window.maxx;
y = n[2];
{
//need to draw an initial segment from clippedx,cur_y to clippedx,intersecty
n[2] = cur_y + (window.maxx - cur_x) * dy / dx;
-
+
move_pen(window.maxx,(int)floor(cur_y));
draw_line(window.maxx,cur_y,window.maxx,n[2]);
-
+
cur_x = window.maxx;
cur_y = n[2];
}
-
- //generate data for the ending clipped info
+
+ //generate data for the ending clipped info
if(x < window.minx)
{
//intial line to intersection (and degenerate)
n[2] = y + (window.minx - x) * dy / dx;
-
+
n[0] = window.minx;
n[1] = y;
-
+
//intersect coords
x = window.minx;
y = n[2];
afterx = true;
}
}
-
+
move_pen((int)floor(cur_x),(int)floor(cur_y));
//draw the relevant line (clipped)
draw_line(cur_x,cur_y,x,y);
-
+
if(afterx)
{
draw_line(x,y,n[0],n[1]);
}
-
+
cur_x = xin;
cur_y = yin;
}
(maxx < r.minx) ||
(miny > r.maxy) ||
(maxy < r.miny);*/
-
+
return ((p[0][0] > r.maxx) & (p[1][0] > r.maxx) & (p[2][0] > r.maxx) & (p[3][0] > r.maxx)) |
((p[0][0] < r.minx) & (p[1][0] < r.minx) & (p[2][0] < r.minx) & (p[3][0] < r.minx)) |
((p[0][1] > r.maxy) & (p[1][1] > r.maxy) & (p[2][1] > r.maxy) & (p[3][1] > r.maxy)) |
{
const Real x1 = p[1][0] - p[0][0];
const Real y1 = p[1][1] - p[0][1];
-
+
const Real x2 = p[2][0] - p[1][0];
const Real y2 = p[2][1] - p[1][1];
-
+
const Real x3 = p[3][0] - p[2][0];
const Real y3 = p[3][1] - p[2][1];
-
+
const Real d1 = x1*x1 + y1*y1;
const Real d2 = x2*x2 + y2*y2;
const Real d3 = x3*x3 + y3*y3;
-
+
return max(max(d1,d2),d3);
}
{
const Real x1 = p[1][0] - p[0][0];
const Real y1 = p[1][1] - p[0][1];
-
+
const Real x2 = p[2][0] - p[1][0];
const Real y2 = p[2][1] - p[1][1];
-
+
const Real d1 = x1*x1 + y1*y1;
const Real d2 = x2*x2 + y2*y2;
-
+
return max(d1,d2);
}
int level = 0;
int num = 0;
bool onsecond = false;
-
+
arc[0] = Point(x,y);
arc[1] = Point(x1,y1);
arc[2] = Point(cur_x,cur_y);
-
+
//just draw the line if it's outside
if(clip_conic(arc,window))
{
line_to(x,y);
return;
}
-
+
//Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
while(current >= arc)
{
if(num >= MAX_SUBDIVISION_SIZE)
{
warning("Curve subdivision somehow ran out of space while tesselating!");
-
+
//do something...
assert(0);
return;
//cur_x,cur_y = current[2], so we need to go 1,0
line_to(current[1][0],current[1][1]);
line_to(current[0][0],current[0][1]);
-
+
current -= 2;
if(onsecond) level--;
num--;
int num = 0;
int level = 0;
bool onsecond = false;
-
+
arc[0] = Point(x,y);
arc[1] = Point(x2,y2);
arc[2] = Point(x1,y1);
arc[3] = Point(cur_x,cur_y);
-
+
//just draw the line if it's outside
if(clip_cubic(arc,window))
{
line_to(x,y);
return;
}
-
+
//Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first)
while(current >= arc) //once current goes below arc, there are no more curves left
{
if(num >= MAX_SUBDIVISION_SIZE)
{
warning("Curve subdivision somehow ran out of space while tesselating!");
-
+
//do something...
assert(0);
return;
}else
-
- //if we are not at the level minimum
+
+ //if we are not at the level minimum
if(level < MIN_SUBDIVISION_DRAW_LEVELS)
{
Subd_Cubic_Stack(current);
onsecond = true;
num --;
continue;
- }
+ }
else
//split it again, if it's too big
if(max_edges_cubic(current) > 0.25) //could use max_edges<3>
line_to(current[2][0],current[2][1]);
line_to(current[1][0],current[1][1]);
line_to(current[0][0],current[0][1]);
-
+
current -= 3;
if(onsecond) level--;
num --;
onsecond = true;
}
- }
+ }
}
//******************** LINE ALGORITHMS ****************************
-// THESE CALCULATE THE AREA AND THE COVER FOR THE MARKS, TO THEN SCAN CONVERT
-// - BROKEN UP INTO SCANLINES (draw_line - y intersections),
+// THESE CALCULATE THE AREA AND THE COVER FOR THE MARKS, TO THEN SCAN CONVERT
+// - BROKEN UP INTO SCANLINES (draw_line - y intersections),
// THEN THE COVER AND AREA PER TOUCHED PIXEL IS CALCULATED (draw_scanline - x intersections)
void Layer_Shape::PolySpan::draw_scanline(int y, Real x1, Real fy1, Real x2, Real fy2)
{
int ix2 = (int)floor(x2);
Real fx1 = x1 - ix1;
Real fx2 = x2 - ix2;
-
+
Real dx,dy,dydx,mult;
-
+
dx = x2 - x1;
dy = fy2 - fy1;
-
+
//case horizontal line
if(fy1 == fy2)
{
move_pen(ix2,y); //pen needs to be at the last coord
return;
}
-
+
//case all in same pixel
if(ix1 == ix2) //impossible for degenerate case (covered by the previous cases)
{
{
// ----> fx1...1 0...1 ... 0...1 0...fx2
dydx = dy / dx;
-
+
//set initial values
//Iterate through the covered pixels
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
-
+
//move to the next pixel
fy1 += mult;
ix1++;
-
+
move_pen(ix1,y);
-
+
//set up for whole ones
while(ix1 != ix2)
{
//trapezoid(0,y1,1,y1+dydx);
- current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
-
+ current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
+
//move to next pixel (+1)
ix1++;
fy1 += dydx;
move_pen(ix1,y);
}
-
+
//last pixel
//final y-pos - last intersect pos
mult = fx2 * dydx;
//mult = (0 - fx1) * dy / dx;
//neg sign sucked into dydx
dydx = -dy / dx;
-
+
//set initial values
//Iterate through the covered pixels
mult = fx1*dydx; //next y intersection diff value
-
+
//first pixel
current.addcover(mult,fx1*mult/2); // fx1,fy1,0,fy@0 - starting trapazoidal area
-
+
//move to next pixel
fy1 += mult;
ix1--;
-
+
move_pen(ix1,y);
-
+
//set up for whole ones
while(ix1 != ix2)
{
//trapezoid(0,y1,1,y1+dydx);
- current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
-
+ current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover
+
//move to next pixel (-1)
fy1 += dydx;
ix1--;
move_pen(ix1,y);
}
-
+
//last pixel
mult = fy2 - fy1; //final y-pos - last intersect pos
-
+
current.addcover(mult,(fx2+1)*mult/2);
}
}
assert(!isnan(fy1));
assert(!isnan(fy2));
-
+
Real dx,dy,dxdy,mult,x_from,x_to;
-
+
const Real SLOPE_EPSILON = 1e-10;
-
+
//case all one scanline
if(iy1 == iy2)
{
draw_scanline(iy1,x1,y1,x2,y2);
return;
}
-
+
//difference values
dy = y2 - y1;
- dx = x2 - x1;
-
+ dx = x2 - x1;
+
//case vertical line
if(dx < SLOPE_EPSILON && dx > -SLOPE_EPSILON)
{
- //calc area and cover on vertical line
+ //calc area and cover on vertical line
if(dy > 0)
{
// ----> fx1...1 0...1 ... 0...1 0...fx2
Real sub;
-
+
int ix1 = (int)floor(x1);
Real fx1 = x1 - ix1;
-
+
//current pixel
sub = 1 - fy1;
-
+
current.addcover(sub,fx1*sub);
-
+
//next pixel
iy1++;
//move pen to next pixel
move_pen(ix1,iy1);
-
+
while(iy1 != iy2)
- {
+ {
//accumulate cover
current.addcover(1,fx1);
-
+
//next pixel
iy1++;
move_pen(ix1,iy1);
}
-
+
//last pixel
current.addcover(fy2,fy2*fx1);
}else
{
Real sub;
-
+
int ix1 = (int)floor(x1);
Real fx1 = x1 - ix1;
-
+
//current pixel
sub = 0 - fy1;
-
+
current.addcover(sub,fx1*sub);
-
+
//next pixel
iy1--;
-
+
move_pen(ix1,iy1);
-
+
while(iy1 != iy2)
{
//accumulate in current pixel
current.addcover(-1,-fx1);
-
+
//move to next
iy1--;
move_pen(ix1,iy1);
}
-
+
current.addcover(fy2-1,(fy2-1)*fx1);
}
return;
}
//case normal line - guaranteed dx != 0 && dy != 0
-
+
//calculate the initial intersection with "next" scanline
if(dy > 0)
{
dxdy = dx / dy;
-
+
mult = (1 - fy1) * dxdy;
-
- //x interset scanline
+
+ //x interset scanline
x_from = x1 + mult;
draw_scanline(iy1,x1,fy1,x_from,1);
-
+
//move to next line
iy1++;
-
+
move_pen((int)floor(x_from),iy1);
-
+
while(iy1 != iy2)
{
//keep up on the x axis, and render the current scanline
x_to = x_from + dxdy;
draw_scanline(iy1,x_from,0,x_to,1);
x_from = x_to;
-
+
//move to next pixel
iy1++;
move_pen((int)floor(x_from),iy1);
}
-
+
//draw the last one, fractional
draw_scanline(iy2,x_from,0,x2,fy2);
-
+
}else
{
dxdy = -dx / dy;
-
+
mult = fy1 * dxdy;
-
+
//x interset scanline
x_from = x1 + mult;
draw_scanline(iy1,x1,fy1,x_from,0);
-
+
//each line after
iy1--;
-
+
move_pen((int)floor(x_from),iy1);
-
+
while(iy1 != iy2)
{
x_to = x_from + dxdy;
draw_scanline(iy1,x_from,1,x_to,0);
x_from = x_to;
-
+
iy1--;
move_pen((int)floor(x_from),iy1);
}
//const int sizeblock = sizeof(Primitive)+sizeof(Point);
Primitive op;
Point p(x,y);
-
+
op.operation = Primitive::MOVE_TO;
op.number = 1; //one point for now
-
+
if(lastbyteop == Primitive::MOVE_TO)
{
char *ptr = &bytestream[lastoppos];
{
lastbyteop = Primitive::MOVE_TO;
lastoppos = bytestream.size();
-
+
bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
}
-
+
edge_table->move_to(x,y);
}
void Layer_Shape::close()
{
Primitive op;
-
+
op.operation = Primitive::CLOSE;
op.number = 0;
-
+
if(lastbyteop == Primitive::CLOSE)
{
}else
{
lastbyteop = Primitive::CLOSE;
lastoppos = bytestream.size();
-
+
bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert header
}
-
+
edge_table->close();
//should not affect the bounding box since it would just be returning to old point...
}
void Layer_Shape::endpath()
{
Primitive op;
-
+
op.operation = Primitive::END;
op.number = 0;
-
+
if(lastbyteop == Primitive::END | lastbyteop == Primitive::NONE)
{
}else
{
assert(!isnan(x));
assert(!isnan(y));
-
+
//const int sizeblock = sizeof(Primitive)+sizeof(Point);
Primitive op;
Point p(x,y);
-
+
op.operation = Primitive::LINE_TO;
op.number = 1; //one point for now
-
+
if(lastbyteop == Primitive::MOVE_TO | lastbyteop == Primitive::LINE_TO)
{
//only need to insert the point
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
-
+
Primitive * prim = (Primitive *)&bytestream[lastoppos];
prim->number++; //increment number of points in the list
}else
{
lastbyteop = Primitive::LINE_TO;
lastoppos = bytestream.size();
-
+
bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
}
-
+
edge_table->line_to(x,y);
}
Primitive op;
Point p(x,y);
Point p1(x1,y1);
-
+
op.operation = Primitive::CONIC_TO;
op.number = 2; //2 points for now
-
+
if(lastbyteop == Primitive::CONIC_TO)
{
//only need to insert the new points
bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
-
+
Primitive * prim = (Primitive *)&bytestream[lastoppos];
prim->number += 2; //increment number of points in the list
}else
{
lastbyteop = Primitive::CONIC_TO;
lastoppos = bytestream.size();
-
+
bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
}
-
+
edge_table->conic_to(x1,y1,x,y);
}
//const int sizeblock = sizeof(Primitive)+sizeof(Point);
Primitive op;
Point p(x,y);
-
+
op.operation = Primitive::CONIC_TO_SMOOTH;
op.number = 1; //2 points for now
-
+
if(lastbyteop == Primitive::CONIC_TO_SMOOTH)
{
//only need to insert the new point
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
-
+
Primitive * prim = (Primitive *)&bytestream[lastoppos];
prim->number += 1; //increment number of points in the list
}else
{
lastbyteop = Primitive::CONIC_TO_SMOOTH;
lastoppos = bytestream.size();
-
+
bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
}
-
+
edge_table->conic_to_smooth(x,y);
}
Point p(x,y);
Point p1(x1,y1);
Point p2(x2,y2);
-
+
op.operation = Primitive::CUBIC_TO;
op.number = 3; //3 points for now
-
+
if(lastbyteop == Primitive::CUBIC_TO)
{
//only need to insert the new points
bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1));
bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
-
+
Primitive * prim = (Primitive *)&bytestream[lastoppos];
prim->number += 3; //increment number of points in the list
}else
{
lastbyteop = Primitive::CUBIC_TO;
lastoppos = bytestream.size();
-
+
bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data
bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
}
-
+
edge_table->curve_to(x1,y1,x2,y2,x,y);
}
Primitive op;
Point p(x,y);
Point p2(x2,y2);
-
+
op.operation = Primitive::CUBIC_TO_SMOOTH;
op.number = 2; //3 points for now
-
+
if(lastbyteop == Primitive::CUBIC_TO_SMOOTH)
{
//only need to insert the new points
bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1));
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1));
-
+
Primitive * prim = (Primitive *)&bytestream[lastoppos];
prim->number += 2; //increment number of points in the list
}else
{
lastbyteop = Primitive::CUBIC_TO_SMOOTH;
lastoppos = bytestream.size();
-
+
bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header
bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data
bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data
// ACCELERATED RENDER FUNCTION - TRANSLATE BYTE CODE INTO FUNCTION CALLS
-bool Layer_Shape::render_polyspan(Surface *surface, PolySpan &polyspan,
+bool Layer_Shape::render_polyspan(Surface *surface, PolySpan &polyspan,
Color::BlendMethod got_blend_method, Color::value_type got_amount) const
{
Surface::alpha_pen p(surface->begin(),got_amount,_BlendFunc(got_blend_method));
PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
Real cover,area,alpha;
-
+
int y,x;
-
+
p.set_value(color);
cover = 0;
-
+
if(cur_mark == end_mark)
{
//no marks at all
}
return true;
}
-
+
//fill initial rect / line
if(invert)
{
p.move_to(polyspan.window.minx,polyspan.window.miny);
y = polyspan.window.miny;
int l = polyspan.window.maxx - polyspan.window.minx;
-
+
p.put_block(cur_mark->y - polyspan.window.miny,l);
-
+
//fill the area to the left of the first vertex on that line
l = cur_mark->x - polyspan.window.minx;
p.move_to(polyspan.window.minx,cur_mark->y);
if(l) p.put_hline(l);
}
-
+
for(;;)
{
y = cur_mark->y;
x = cur_mark->x;
-
+
p.move_to(x,y);
-
+
area = cur_mark->area;
cover += cur_mark->cover;
-
+
//accumulate for the current pixel
while(++cur_mark != polyspan.covers.end())
{
if(y != cur_mark->y | x != cur_mark->x)
break;
-
+
area += cur_mark->area;
cover += cur_mark->cover;
}
-
+
//draw pixel - based on covered area
if(area) //if we're ok, draw the current pixel
{
alpha = polyspan.ExtractAlpha(cover - area);
if(invert) alpha = 1 - alpha;
-
+
if(!antialias)
{
if(alpha >= .5) p.put_value();
}
else if(alpha) p.put_value_alpha(alpha);
-
+
p.inc_x();
x++;
}
-
+
//if we're done, don't use iterator and exit
if(cur_mark == end_mark) break;
-
+
//if there is no more live pixels on this line, goto next
if(y != cur_mark->y)
{
if(invert)
{
//fill the area at the end of the line
- p.put_hline(polyspan.window.maxx - x);
-
+ p.put_hline(polyspan.window.maxx - x);
+
//fill area at the beginning of the next line
p.move_to(polyspan.window.minx,cur_mark->y);
p.put_hline(cur_mark->x - polyspan.window.minx);
}
-
- cover = 0;
-
+
+ cover = 0;
+
continue;
}
-
+
//draw span to next pixel - based on total amount of pixel cover
if(x < cur_mark->x)
- {
+ {
alpha = polyspan.ExtractAlpha(cover);
if(invert) alpha = 1 - alpha;
else if(alpha) p.put_hline(cur_mark->x - x,alpha);
}
}
-
+
//fill the after stuff
if(invert)
{
//fill the area at the end of the line
- p.put_hline(polyspan.window.maxx - x);
-
+ p.put_hline(polyspan.window.maxx - x);
+
//fill area at the beginning of the next line
p.move_to(polyspan.window.minx,y+1);
p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
}
-
+
return true;
}
PolySpan::cover_array::iterator end_mark = polyspan.covers.end();
Real cover,area,alpha;
-
+
int y,x;
-
- cover = 0;
-
+
+ cover = 0;
+
//the pen always writes 1 (unless told to do otherwise)
p.set_value(1);
-
+
if(cur_mark == end_mark)
{
//no marks at all
}
return true;
}
-
+
//fill initial rect / line
if(invert)
{
p.move_to(polyspan.window.minx,polyspan.window.miny);
y = polyspan.window.miny;
int l = polyspan.window.maxx - polyspan.window.minx;
-
+
p.put_block(cur_mark->y - polyspan.window.miny,l);
-
+
//fill the area to the left of the first vertex on that line
l = cur_mark->x - polyspan.window.minx;
p.move_to(polyspan.window.minx,cur_mark->y);
if(l) p.put_hline(l);
-
+
for(;;)
{
y = cur_mark->y;
x = cur_mark->x;
-
+
p.move_to(x,y);
-
+
area = cur_mark->area;
cover += cur_mark->cover;
-
+
//accumulate for the current pixel
while(++cur_mark != polyspan.covers.end())
{
if(y != cur_mark->y | x != cur_mark->x)
break;
-
+
area += cur_mark->area;
cover += cur_mark->cover;
}
-
+
//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);
if(!antialias)
{
if(alpha >= .5) p.put_value();
}
else if(alpha) p.put_value(alpha);
-
+
p.inc_x();
x++;
}
-
+
//if we're done, don't use iterator and exit
if(cur_mark == end_mark) break;
-
+
//if there is no more live pixels on this line, goto next
if(y != cur_mark->y)
{
//fill the area at the end of the line
p.put_hline(polyspan.window.maxx - x);
-
+
//fill area at the beginning of the next line
p.move_to(polyspan.window.minx,cur_mark->y);
p.put_hline(cur_mark->x - polyspan.window.minx);
-
- cover = 0;
-
+
+ cover = 0;
+
continue;
}
-
+
//draw span to next pixel - based on total amount of pixel cover
if(x < cur_mark->x)
- {
+ {
alpha = 1 - polyspan.ExtractAlpha(cover);
if(!antialias)
{
else if(alpha) p.put_hline(cur_mark->x - x,alpha);
}
}
-
+
//fill the area at the end of the line
- p.put_hline(polyspan.window.maxx - x);
-
+ p.put_hline(polyspan.window.maxx - x);
+
//fill area at the beginning of the next line
p.move_to(polyspan.window.minx,y+1);
p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx);
{
y = cur_mark->y;
x = cur_mark->x;
-
+
p.move_to(x,y);
-
+
area = cur_mark->area;
cover += cur_mark->cover;
-
+
//accumulate for the current pixel
while(++cur_mark != polyspan.covers.end())
{
if(y != cur_mark->y | x != cur_mark->x)
break;
-
+
area += cur_mark->area;
cover += cur_mark->cover;
}
-
+
//draw pixel - based on covered area
if(area) //if we're ok, draw the current pixel
{
if(alpha >= .5) p.put_value();
}
else if(alpha) p.put_value(alpha);
-
+
p.inc_x();
x++;
}
-
+
//if we're done, don't use iterator and exit
if(cur_mark == end_mark) break;
-
+
//if there is no more live pixels on this line, goto next
if(y != cur_mark->y)
- {
- cover = 0;
-
+ {
+ cover = 0;
+
continue;
}
-
+
//draw span to next pixel - based on total amount of pixel cover
if(x < cur_mark->x)
- {
+ {
alpha = polyspan.ExtractAlpha(cover);
if(!antialias)
{
}
}
}
-
+
return true;
}
{
const unsigned int w = renddesc.get_w();
const unsigned int h = renddesc.get_h();
-
+
const Real pw = abs(renddesc.get_pw());
const Real ph = abs(renddesc.get_ph());
-
+
//const Real OFFSET_EPSILON = 1e-8;
SuperCallback stageone(cb,1,10000,15001+renddesc.get_h());
SuperCallback stagetwo(cb,10000,10001+renddesc.get_h(),15001+renddesc.get_h());
SuperCallback stagethree(cb,10001+renddesc.get_h(),15001+renddesc.get_h(),15001+renddesc.get_h());
-
+
// Render what is behind us
-
+
//clip if it satisfies the invert solid thing
if(is_solid_color() && invert)
- {
+ {
Rect aabb = edge_table->aabb;
Point tl = renddesc.get_tl() - offset;
-
+
Real pw = renddesc.get_pw(),
ph = renddesc.get_ph();
Rect nrect;
-
+
Real pixelfeatherx = abs(feather/pw),
pixelfeathery = 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);
-
+
RendDesc optdesc(renddesc);
-
+
//make sure to expand so we gain subpixels rather than lose them
nrect.minx = floor(nrect.minx-pixelfeatherx); nrect.miny = floor(nrect.miny-pixelfeathery);
nrect.maxx = ceil(nrect.maxx+pixelfeatherx); nrect.maxy = ceil(nrect.maxy+pixelfeathery);
-
+
//make sure the subwindow is clipped with our tile window (minimize useless drawing)
set_intersect(nrect,nrect,Rect(0,0,renddesc.get_w(),renddesc.get_h()));
-
+
//must resize the surface first
surface->set_wh(renddesc.get_w(),renddesc.get_h());
surface->clear();
-
+
//only render anything if it's visible from our current tile
if(nrect.valid())
{
//set the subwindow to the viewable pixels and render it to the subsurface
optdesc.set_subwindow((int)nrect.minx, (int)nrect.miny,
(int)(nrect.maxx - nrect.minx), (int)(nrect.maxy - nrect.miny));
-
+
Surface optimizedbacksurf;
if(!context.accelerated_render(&optimizedbacksurf,quality,optdesc,&stageone))
return false;
-
+
//blit that onto the original surface so we can pretend that nothing ever happened
- Surface::pen p = surface->get_pen((int)nrect.minx,(int)nrect.miny);
+ Surface::pen p = surface->get_pen((int)nrect.minx,(int)nrect.miny);
optimizedbacksurf.blit_to(p);
}
}else
if(!context.accelerated_render(surface,quality,renddesc,&stageone))
return false;
}
-
+
if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
-
+
if(feather)
{
//we have to blur rather than be crappy
-
+
//so make a separate surface
RendDesc workdesc(renddesc);
-
+
etl::surface<float> shapesurface;
//the expanded size = 1/2 the size in each direction rounded up
int halfsizex = (int) (abs(feather*.5/pw) + 3),
halfsizey = (int) (abs(feather*.5/ph) + 3);
-
+
//expand by 1/2 size in each direction on either side
switch(blurtype)
{
halfsizey*=2;
}
workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey));
- break;
+ break;
}
case Blur::GAUSSIAN:
- {
+ {
#define GAUSSIAN_ADJUSTMENT (0.05)
Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]);
Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]);
-
+
pw=pw*pw;
ph=ph*ph;
-
+
halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5);
halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5);
-
+
halfsizex = (halfsizex + 1)/2;
halfsizey = (halfsizey + 1)/2;
workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey );
-
+
break;
}
}
-
+
shapesurface.set_wh(workdesc.get_w(),workdesc.get_h());
shapesurface.clear();
-
+
//render the shape
if(!render_shape(&shapesurface,quality,workdesc,&stagetwo))return false;
-
+
//blur the image
Blur(feather,feather,blurtype,&stagethree)(shapesurface,workdesc.get_br()-workdesc.get_tl(),shapesurface);
-
- //blend with stuff below it...
+
+ //blend with stuff below it...
unsigned int u = halfsizex, v = halfsizey, x = 0, y = 0;
for(y = 0; y < h; y++,v++)
{
//else (*surface)[y][x] = worksurface[v][u];
}
}
-
+
//we are done
if(cb && !cb->amount_complete(100,100))
{
synfig::warning("Layer_Shape: could not set amount complete");
return false;
}
-
+
return true;
}else
{
const RendDesc &renddesc, ProgressCallback *cb)const
{
int tmp(0);
-
+
SuperCallback progress(cb,0,renddesc.get_h(),renddesc.get_h());
-
+
// If our amount is set to zero, no need to render anything
if(!get_amount())
return true;
-
+
//test new polygon renderer
// Build edge table
// Width and Height of a pixel
const int h = renddesc.get_h();
const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
-
+
const Point tl = renddesc.get_tl();
-
+
Vector tangent (0,0);
-
+
PolySpan span;
-
+
//optimization for tesselating only inside tiles
span.window.minx = 0;
span.window.miny = 0;
//pointers for processing the bytestream
const char *current = &bytestream[0];
- const char *end = &bytestream[bytestream.size()];
-
+ const char *end = &bytestream[bytestream.size()];
+
int operation = Primitive::NONE;
int number = 0;
int curnum;
-
+
Primitive *curprim;
Point *data;
-
+
Real x,y,x1,y1,x2,y2;
tmp++;
try {
-
+
//get the op code safely
curprim = (Primitive *)current;
-
+
//advance past indices
current += sizeof(Primitive);
if(current > end)
{
warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
- return false;
+ return false;
}
-
+
//get the relevant data
operation = curprim->operation;
number = curprim->number;
-
+
if(operation == Primitive::END)
break;
-
+
if(operation == Primitive::CLOSE)
{
if(span.notclosed())
{
tangent[0] = span.close_x - span.cur_x;
tangent[1] = span.close_y - span.cur_y;
- span.close();
+ span.close();
}
continue;
}
-
+
data = (Point*)current;
current += sizeof(Point)*number;
-
+
//check data positioning
if(current > end)
{
//transfer all the data - RLE optimized
for(curnum=0; curnum < number;)
- {
+ {
switch(operation)
{
case Primitive::MOVE_TO:
x = (x - tl[0] + offset[0])*pw;
y = data[curnum][1];
y = (y - tl[1] + offset[1])*ph;
-
+
if(curnum == 0)
{
span.move_to(x,y);
-
+
tangent[0] = 0;
tangent[1] = 0;
}
{
tangent[0] = x - span.cur_x;
tangent[1] = y - span.cur_y;
-
+
span.line_to(x,y);
}
-
+
curnum++; //only advance one point
-
+
break;
}
-
+
case Primitive::LINE_TO:
{
x = data[curnum][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum][1];
y = (y - tl[1] + offset[1])*ph;
-
+
tangent[0] = x - span.cur_x;
tangent[1] = y - span.cur_y;
-
+
span.line_to(x,y);
curnum++;
break;
}
-
+
case Primitive::CONIC_TO:
{
x = data[curnum+1][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum+1][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x1 = data[curnum][0];
x1 = (x1 - tl[0] + offset[0])*pw;
y1 = data[curnum][1];
y1 = (y1 - tl[1] + offset[1])*ph;
-
+
tangent[0] = 2*(x - x1);
tangent[1] = 2*(y - y1);
-
+
span.conic_to(x1,y1,x,y);
curnum += 2;
break;
}
-
+
case Primitive::CONIC_TO_SMOOTH:
{
x = data[curnum][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x1 = span.cur_x + tangent[0]/2;
y1 = span.cur_y + tangent[1]/2;
tangent[0] = 2*(x - x1);
tangent[1] = 2*(y - y1);
-
+
span.conic_to(x1,y1,x,y);
curnum ++;
-
+
break;
}
-
+
case Primitive::CUBIC_TO:
{
x = data[curnum+2][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum+2][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x2 = data[curnum+1][0];
x2 = (x2 - tl[0] + offset[0])*pw;
y2 = data[curnum+1][1];
y2 = (y2 - tl[1] + offset[1])*ph;
-
+
x1 = data[curnum][0];
x1 = (x1 - tl[0] + offset[0])*pw;
y1 = data[curnum][1];
y1 = (y1 - tl[1] + offset[1])*ph;
-
+
tangent[0] = 2*(x - x2);
tangent[1] = 2*(y - y2);
-
+
span.cubic_to(x1,y1,x2,y2,x,y);
curnum += 3;
-
+
break;
}
-
+
case Primitive::CUBIC_TO_SMOOTH:
{
x = data[curnum+1][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum+1][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x2 = data[curnum][0];
x2 = (x2 - tl[0] + offset[0])*pw;
y2 = data[curnum][1];
y2 = (y2 - tl[1] + offset[1])*ph;
-
- x1 = span.cur_x + tangent[0]/3.0;
+
+ x1 = span.cur_x + tangent[0]/3.0;
y1 = span.cur_y + tangent[1]/3.0;
-
+
tangent[0] = 2*(x - x2);
tangent[1] = 2*(y - y2);
-
+
span.cubic_to(x1,y1,x2,y2,x,y);
curnum += 2;
-
+
break;
}
}
}
}
-
+
//sort the bastards so we can render everything
span.sort_marks();
-
- return render_polyspan(surface, span,
- useblend?get_blend_method():Color::BLEND_STRAIGHT,
+
+ return render_polyspan(surface, span,
+ useblend?get_blend_method():Color::BLEND_STRAIGHT,
useblend?get_amount():1.0);
}
// If our amount is set to zero, no need to render anything
if(!get_amount())
return true;
-
+
//test new polygon renderer
// Build edge table
// Width and Height of a pixel
const int h = renddesc.get_h();
const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
-
+
const Point tl = renddesc.get_tl();
-
+
Vector tangent (0,0);
-
+
PolySpan span;
-
+
//optimization for tesselating only inside tiles
span.window.minx = 0;
span.window.miny = 0;
//pointers for processing the bytestream
const char *current = &bytestream[0];
- const char *end = &bytestream[bytestream.size()];
-
+ const char *end = &bytestream[bytestream.size()];
+
int operation = Primitive::NONE;
int number = 0;
int curnum;
-
+
Primitive *curprim;
Point *data;
-
+
Real x,y,x1,y1,x2,y2;
-
+
while(current < end)
{
//get the op code safely
curprim = (Primitive *)current;
-
+
//advance past indices
current += sizeof(Primitive);
if(current > end)
{
warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration");
- return false;
+ return false;
}
-
+
//get the relevant data
operation = curprim->operation;
number = curprim->number;
-
+
if(operation == Primitive::END)
break;
-
+
if(operation == Primitive::CLOSE)
{
if(span.notclosed())
{
tangent[0] = span.close_x - span.cur_x;
tangent[1] = span.close_y - span.cur_y;
- span.close();
+ span.close();
}
continue;
}
-
+
data = (Point*)current;
current += sizeof(Point)*number;
-
+
//check data positioning
if(current > end)
{
//transfer all the data
for(curnum=0; curnum < number;)
- {
+ {
switch(operation)
{
case Primitive::MOVE_TO:
x = (x - tl[0] + offset[0])*pw;
y = data[curnum][1];
y = (y - tl[1] + offset[1])*ph;
-
+
if(curnum == 0)
{
span.move_to(x,y);
-
+
tangent[0] = 0;
tangent[1] = 0;
}
{
tangent[0] = x - span.cur_x;
tangent[1] = y - span.cur_y;
-
+
span.line_to(x,y);
}
-
+
curnum++; //only advance one point
-
+
break;
}
-
+
case Primitive::LINE_TO:
{
x = data[curnum][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum][1];
y = (y - tl[1] + offset[1])*ph;
-
+
tangent[0] = x - span.cur_x;
tangent[1] = y - span.cur_y;
-
+
span.line_to(x,y);
curnum++;
break;
}
-
+
case Primitive::CONIC_TO:
{
x = data[curnum+1][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum+1][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x1 = data[curnum][0];
x1 = (x1 - tl[0] + offset[0])*pw;
y1 = data[curnum][1];
y1 = (y1 - tl[1] + offset[1])*ph;
-
+
tangent[0] = 2*(x - x1);
tangent[1] = 2*(y - y1);
-
+
span.conic_to(x1,y1,x,y);
curnum += 2;
break;
}
-
+
case Primitive::CONIC_TO_SMOOTH:
{
x = data[curnum][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x1 = span.cur_x + tangent[0]/2;
y1 = span.cur_y + tangent[1]/2;
tangent[0] = 2*(x - x1);
tangent[1] = 2*(y - y1);
-
+
span.conic_to(x1,y1,x,y);
curnum ++;
-
+
break;
}
-
+
case Primitive::CUBIC_TO:
{
x = data[curnum+2][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum+2][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x2 = data[curnum+1][0];
x2 = (x2 - tl[0] + offset[0])*pw;
y2 = data[curnum+1][1];
y2 = (y2 - tl[1] + offset[1])*ph;
-
+
x1 = data[curnum][0];
x1 = (x1 - tl[0] + offset[0])*pw;
y1 = data[curnum][1];
y1 = (y1 - tl[1] + offset[1])*ph;
-
+
tangent[0] = 2*(x - x2);
tangent[1] = 2*(y - y2);
-
+
span.cubic_to(x1,y1,x2,y2,x,y);
curnum += 3;
-
+
break;
}
-
+
case Primitive::CUBIC_TO_SMOOTH:
{
x = data[curnum+1][0];
x = (x - tl[0] + offset[0])*pw;
y = data[curnum+1][1];
y = (y - tl[1] + offset[1])*ph;
-
+
x2 = data[curnum][0];
x2 = (x2 - tl[0] + offset[0])*pw;
y2 = data[curnum][1];
y2 = (y2 - tl[1] + offset[1])*ph;
-
- x1 = span.cur_x + tangent[0]/3.0;
+
+ x1 = span.cur_x + tangent[0]/3.0;
y1 = span.cur_y + tangent[1]/3.0;
-
+
tangent[0] = 2*(x - x2);
tangent[1] = 2*(y - y2);
-
+
span.cubic_to(x1,y1,x2,y2,x,y);
curnum += 2;
-
+
break;
}
}
}
}
-
+
//sort the bastards so we can render everything
span.sort_marks();
-
+
return render_polyspan(surface, span);
}
Rect bounds(edge_table->aabb+offset);
bounds.expand(max((bounds.get_min()-bounds.get_max()).mag()*0.01,feather));
-
-
+
+
return bounds;
}
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
/*! \class Layer_Shape
** \beief writeme */
class Layer_Shape : public Layer_Composite, public Layer_NoDeform
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
-
+
//internal cacheing
struct Intersector;
Intersector *edge_table;
-
+
//exported data
Color color;
-
+
Point offset;
bool invert;
bool antialias;
-
+
int blurtype;
Real feather;
-
+
std::vector< char > bytestream;
-
+
//for use in creating the bytestream
int lastbyteop;
int lastoppos;
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
-
+
virtual Vocab get_param_vocab()const;
virtual Color get_color(Context context, const Point &pos)const;
color(Color::black())
{
}
-
+
bool
Layer_SolidColor::set_param(const String & param, const ValueBase &value)
{
IMPORT(color);
-
+
return Layer_Composite::set_param(param,value);
}
EXPORT_NAME();
EXPORT_VERSION();
-
- return Layer_Composite::get_param(param);
+
+ return Layer_Composite::get_param(param);
}
Layer::Vocab
Layer_SolidColor::get_param_vocab()const
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
-
+
ret.push_back(ParamDesc("color")
.set_local_name(_("Color"))
);
-
+
return ret;
}
else
if(get_blend_method()==Color::BLEND_COMPOSITE && get_amount()*color.get_a()>=0.5)
return const_cast<Layer_SolidColor*>(this);
-
+
Layer::Handle layer(context.hit_check(point));
-
+
return layer?layer:const_cast<Layer_SolidColor*>(this);
}
else
return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method());
}
-
+
bool
Layer_SolidColor::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
// Mark our progress as starting
if(cb && !cb->amount_complete(0,1000))
return false;
-
+
surface->set_wh(renddesc.get_w(),renddesc.get_h());
surface->fill(color);
class Layer_SolidColor : public Layer_Composite, public Layer_NoDeform
{
SYNFIG_LAYER_MODULE_EXT
-
+
private:
Color color;
public:
-
+
Layer_SolidColor();
-
+
virtual bool set_param(const String & param, const synfig::ValueBase &value);
virtual ValueBase get_param(const String & param)const;
virtual Color get_color(Context context, const Point &pos)const;
-
+
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
-
+
virtual Vocab get_param_vocab()const;
virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;
// DEBUGPOINT();
int frame=static_cast<int>(time*fps);
// DEBUGPOINT();
-
+
if(!filename_list.size())
{
if(cb)cb->error(_("No images in list"));
else synfig::error(_("No images in list"));
return false;
}
-
+
// DEBUGPOINT();
if(frame<0)frame=0;
if(frame>=(signed)filename_list.size())frame=filename_list.size()-1;
-
+
// DEBUGPOINT();
// See if that frame is cached
std::list<std::pair<int,Surface> >::iterator iter;
return static_cast<bool>(surface);
}
}
-
+
Importer::Handle importer(Importer::open(filename_list[frame]));
-
+
// DEBUGPOINT();
if(!importer)
else synfig::error(_("Unable to open ")+filename_list[frame]);
return false;
}
-
+
// DEBUGPOINT();
if(!importer->get_frame(surface,0,cb))
else synfig::error(_("Unable to get frame from ")+filename_list[frame]);
return false;
}
-
+
// DEBUGPOINT();
if(frame_cache.size()>=LIST_IMPORTER_CACHE_SIZE)
// DEBUGPOINT();
- frame_cache.push_back(std::pair<int,Surface>(frame,surface));
+ frame_cache.push_back(std::pair<int,Surface>(frame,surface));
// DEBUGPOINT();
static Importer* create(const char *filename);
};
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
int test_class::bleh(0);
test_class test_class_instance;
-*/
+*/
/* === M A C R O S ========================================================= */
static void _canvas_file_name_changed(Canvas *x)
{
std::map<synfig::String, etl::loose_handle<Canvas> >::iterator iter;
-
+
for(iter=get_open_canvas_map().begin();iter!=get_open_canvas_map().end();++iter)
if(iter->second==x)
break;
return;
get_open_canvas_map().erase(iter->first);
get_open_canvas_map()[etl::absolute_path(x->get_file_name())]=x;
-
+
}
Canvas::Handle
if(parser.error_count())
return Canvas::Handle();
-
+
return canvas;
}
if(parser.error_count())
return Canvas::Handle();
-
+
return canvas;
}
error(element,strprintf(_("<%s> is missing \"%s\" attribute"),"real","time"));
return Keyframe();
}
-
+
Keyframe ret(Time(element->get_attribute("time")->get_value(),canvas->rend_desc().get_frame_rate()));
if(element->get_children().empty())
return ret;
-
+
if(element->get_child_text()->get_content().empty())
return ret;
-
+
ret.set_description(element->get_child_text()->get_content());
- return ret;
+ return ret;
}
warning(element, "Undefined value in <string>");
return synfig::String();
}
-
+
if(element->get_child_text()->get_content().empty())
{
warning(element, "Content element of <string> appears to be empty");
return synfig::String();
}
-
+
return element->get_child_text()->get_content();
}
return false;
error(element,strprintf(_("Bad value \"%s\" in <%s>"),val.c_str(),"bool"));
-
+
return false;
}
{
assert(node->get_name()=="gradient");
Gradient ret;
-
+
xmlpp::Element::NodeList list = node->get_children();
for(xmlpp::Element::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
{
}
cpoint.pos=atof(child->get_attribute("pos")->get_value().c_str());
-
+
ret.push_back(cpoint);
}
}
ret.set_vertex(parse_vector(dynamic_cast<xmlpp::Element*>(*iter),canvas));
}
else
- // Tangent 1
+ // Tangent 1
if(child->get_name()=="t1" || child->get_name()=="tangent")
{
xmlpp::Element::NodeList list = child->get_children();
ret.set_tangent1(parse_vector(dynamic_cast<xmlpp::Element*>(*iter),canvas));
}
else
- // Tangent 2
+ // Tangent 2
if(child->get_name()=="t2")
{
xmlpp::Element::NodeList list = child->get_children();
error(element,"Bad type in <animated>");
return ValueNode_Animated::Handle();
}
-
+
ValueNode_Animated::Handle value_node=ValueNode_Animated::create(type);
if(!value_node)
Time time(child->get_attribute("time")->get_value(),canvas->rend_desc().get_frame_rate());
-
+
ValueNode::Handle waypoint_value_node;
-
+
if(child->get_attribute("use"))
{
waypoint_value_node=canvas->surefind_value_node(child->get_attribute("use")->get_value());
error(child, strprintf(_("<%s> is missing its data"),"waypoint"));
continue;
}
-
+
xmlpp::Element::NodeList list = child->get_children();
xmlpp::Element::NodeList::iterator iter;
-
+
// Search for the first non-text XML element
for(iter = list.begin(); iter != list.end(); ++iter)
if(dynamic_cast<xmlpp::Element*>(*iter)) break;
-
+
if(iter==list.end())
{
error(child, strprintf(_("<%s> is missing its data"),"waypoint"));
continue;
}
-
+
waypoint_value_node=parse_value_node(dynamic_cast<xmlpp::Element*>(*iter),canvas);
-
+
/*
ValueBase data=parse_value(dynamic_cast<xmlpp::Element*>(*iter),canvas);
-
+
if(!data.is_valid())
{
error(child,_("Bad data for <waypoint>"));
error(child,_("Bad data for <waypoint>"));
continue;
}
-
+
/*! HACK -- This is a temporary fix to help repair some
** weirdness that is currently going on (10-21-2004).
** This short circuits the linking of waypoints,
** away with something like this pretty easily.
*/
waypoint_value_node=waypoint_value_node->clone();
-
+
// Warn if there is trash after the param value
for(iter++; iter != list.end(); ++iter)
if(dynamic_cast<xmlpp::Element*>(*iter))
else
error(child,strprintf(_("\"%s\" not a valid value for attribute \"%s\" in <%s>"),val.c_str(),"before","waypoint"));
}
-
+
if(child->get_attribute("after"))
{
string val=child->get_attribute("after")->get_value();
CanvasParser::parse_timedswap(xmlpp::Element *node,Canvas::Handle canvas)
{
ValueNode_TimedSwap::Handle timed_swap(parse_linkable_value_node(node,canvas));
-
+
assert(timed_swap);
ValueNode_Animated::Handle animated(ValueNode_Animated::create(timed_swap->get_type()));
animated->set_root_canvas(canvas->get_root());
-
+
assert(animated);
-
+
Time swap_time, swap_length;
(*timed_swap->get_swap_time())(0).put(&swap_time);
(*timed_swap->get_swap_length())(0).put(&swap_length);
-
+
animated->new_waypoint(swap_time-swap_length,timed_swap->get_before());
animated->new_waypoint(swap_time,timed_swap->get_after());
-
+
return animated;
}
if(element->get_attribute("lhs"))
{
lhs=canvas->surefind_value_node(element->get_attribute("lhs")->get_value());
- value_node->set_lhs(lhs);
+ value_node->set_lhs(lhs);
}
-
+
if(element->get_attribute("rhs"))
{
rhs=canvas->surefind_value_node(element->get_attribute("rhs")->get_value());
{
error(element,"Unable to open external file referenced in ID");
}
-
+
xmlpp::Element::NodeList list = element->get_children();
for(xmlpp::Element::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
{
{
handle<LinkableValueNode> value_node;
ValueBase::Type type;
-
+
// Determine the type
if(element->get_attribute("type"))
{
}
value_node=LinkableValueNode::create(element->get_name(),type);
-
+
if(!value_node)
{
error(element,"Unknown ValueNode type "+element->get_name());
return 0;
- }
+ }
if(value_node->get_type()!=type)
{
error(element,"ValueNode did not accept type");
return 0;
- }
+ }
value_node->set_root_canvas(canvas->get_root());
if(element->get_attribute(value_node->link_name(i)))
try {
String id(element->get_attribute(value_node->link_name(i))->get_value());
-
+
if(!value_node->set_link(i,
canvas->surefind_value_node(
id
)
)
- ) error(element,strprintf(_("Unable to set link \"%s\" to ValueNode \"%s\" (link #%d in \"%s\")"),value_node->link_name(i).c_str(),id.c_str(),i,value_node->get_name().c_str()));
+ ) error(element,strprintf(_("Unable to set link \"%s\" to ValueNode \"%s\" (link #%d in \"%s\")"),value_node->link_name(i).c_str(),id.c_str(),i,value_node->get_name().c_str()));
}
catch(Exception::IDNotFound)
{
element->get_attribute(value_node->link_name(i))->get_value().c_str()));
throw;
}
- }
-
+ }
+
xmlpp::Element::NodeList list = element->get_children();
}
// \todo do a search for more elements and warn if they are found
-
+
}
catch(Exception::BadLinkName)
{
{
error(child,strprintf(_("<%s> has a bad value"),name.c_str()));
break;
- }
+ }
// \todo do a search for more elements and warn if they are found
break;
CanvasParser::parse_dynamic_list(xmlpp::Element *element,Canvas::Handle canvas)
{
assert(element->get_name()=="dynamic_list" || element->get_name()=="bline");
-
+
const float fps(canvas?canvas->rend_desc().get_frame_rate():0);
if(!element->get_attribute("type"))
else
bline_value_node->set_loop(false);
}
-
- }
+
+ }
else
value_node=ValueNode_DynamicList::create(type);
if(child->get_name()=="entry")
{
ValueNode_DynamicList::ListEntry list_entry;
-
+
// Parse begin/end waypoints
{
typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
String begin_sequence;
String end_sequence;
-
+
ActivepointList &timing_info(list_entry.timing_info);
-
+
if(child->get_attribute("begin"))
begin_sequence=child->get_attribute("begin")->get_value();
if(child->get_attribute("off"))
end_sequence=child->get_attribute("off")->get_value();
-
+
// clear out any auto-start
if(!begin_sequence.empty())
timing_info.clear();
-
+
//! \optimize
while(!begin_sequence.empty())
{
String::iterator iter(find(begin_sequence.begin(),begin_sequence.end(),','));
- String timecode(begin_sequence.begin(), iter);
+ String timecode(begin_sequence.begin(), iter);
int priority=0;
-
+
// If there is a priority, then grab it and remove
// it from the timecode
if(timecode[0]=='p')
timecode=String(timecode.begin()+space+1,timecode.end());
//synfig::info("priority: %d timecode: %s",priority,timecode.c_str());
}
-
+
timing_info.push_back(
Activepoint(
Time(
priority
)
);
-
+
if(iter==begin_sequence.end())
begin_sequence.clear();
else
while(!end_sequence.empty())
{
String::iterator iter(find(end_sequence.begin(),end_sequence.end(),','));
- String timecode(end_sequence.begin(), iter);
+ String timecode(end_sequence.begin(), iter);
int priority=0;
-
+
// If there is a priority, then grab it and remove
// it from the timecode
if(timecode[0]=='p')
timecode=String(timecode.begin()+space+1,timecode.end());
//synfig::info("priority: %d timecode: %s",priority,timecode.c_str());
}
-
+
timing_info.push_back(
Activepoint(
Time(
else
end_sequence=String(iter+1,end_sequence.end());
}
-
+
timing_info.sort();
}
{
handle<ValueNode> value_node;
assert(element);
-
+
GUID guid;
-
+
if(element->get_attribute("guid"))
{
guid=GUID(element->get_attribute("guid")->get_value())^canvas->get_root()->get_guid();
if(value_node)
return value_node;
}
-
+
// If ValueBase::ident_type() recognises the name, then we know it's a ValueBase
if(element->get_name()!="canvas" && ValueBase::ident_type(element->get_name()))
- {
+ {
ValueBase data=parse_value(element,canvas);
if(!data.is_valid())
if(element->get_name()=="timed_swap")
value_node=parse_timedswap(element,canvas);
else
- if(LinkableValueNode::book().count(element->get_name()))
+ if(LinkableValueNode::book().count(element->get_name()))
value_node=parse_linkable_value_node(element,canvas);
else
if(element->get_name()=="canvas")
error(element, "Expected a ValueNode");
}
-
+
value_node->set_root_canvas(canvas->get_root());
-
-
+
+
// If we were successful, and our element has
// an ID attribute, go ahead and add it to the
// value_node list
catch(Exception::BadLinkName)
{
warning(element,strprintf(_("Bad ID \"%s\""),id.c_str()));
- return value_node;
+ return value_node;
}
catch(Exception::IDAlreadyExists)
{
Layer::Handle
CanvasParser::parse_layer(xmlpp::Element *element,Canvas::Handle canvas)
{
-
+
assert(element->get_name()=="layer");
Layer::Handle layer;
// Handle the description
if(element->get_attribute("desc"))
layer->set_description(element->get_attribute("desc")->get_value());
-
+
if(element->get_attribute("active"))
layer->set_active(element->get_attribute("active")->get_value()=="false"?false:true);
for(iter++; iter != list.end(); ++iter)
if(dynamic_cast<xmlpp::Element*>(*iter))
warning((*iter),strprintf(_("Unexpected element <%s> after <param> data, ignoring..."),(*iter)->get_name().c_str()));
- continue;
+ continue;
}
else
error_unexpected_element(child,child->get_name());
Canvas::Handle
CanvasParser::parse_canvas(xmlpp::Element *element,Canvas::Handle parent,bool inline_, String filename)
{
-
+
if(element->get_name()!="canvas")
{
error_unexpected_element(element,element->get_name(),"canvas");
}
Canvas::Handle canvas;
-
-
+
+
if(parent && (element->get_attribute("id") || inline_))
{
if(inline_)
if(element->get_attribute("yres"))
canvas->rend_desc().set_y_res(atof(element->get_attribute("yres")->get_value().c_str()));
-
+
if(element->get_attribute("fps"))
canvas->rend_desc().set_frame_rate(atof(element->get_attribute("fps")->get_value().c_str()));
{
string values=element->get_attribute("bgcolor")->get_value();
Color bg;
-
+
bg.set_r(atof(string(values.data(),values.find(' ')).c_str()));
values=string(values.begin()+values.find(' ')+1,values.end());
-
+
bg.set_g(atof(string(values.data(),values.find(' ')).c_str()));
values=string(values.begin()+values.find(' ')+1,values.end());
-
+
bg.set_b(atof(string(values.data(),values.find(' ')).c_str()));
values=string(values.begin()+values.find(' ')+1,values.end());
-
+
bg.set_a(atof(values.c_str()));
canvas->rend_desc().set_bg_color(bg);
warning(child,_("Inline canvases cannot have metadata"));
continue;
}
-
+
String name,content;
-
+
if(!child->get_attribute("name"))
{
warning(child,_("<meta> must have a name"));
warning(child,_("<meta> must have content"));
continue;
}
-
+
canvas->set_meta_data(child->get_attribute("name")->get_value(),child->get_attribute("content")->get_value());
}
else if(child->get_name()=="name")
{
xmlpp::Element::NodeList list = child->get_children();
-
+
// If we don't have any name, warn
if(list.empty())
warning(child,_("blank \"name\" entitity"));
-
+
string tmp;
for(xmlpp::Element::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
if(dynamic_cast<xmlpp::TextNode*>(*iter))tmp+=dynamic_cast<xmlpp::TextNode*>(*iter)->get_content();
else
if(child->get_name()=="desc")
{
-
+
xmlpp::Element::NodeList list = child->get_children();
-
+
// If we don't have any description, warn
if(list.empty())
warning(child,_("blank \"desc\" entitity"));
-
+
string tmp;
for(xmlpp::Element::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
if(dynamic_cast<xmlpp::TextNode*>(*iter))tmp+=dynamic_cast<xmlpp::TextNode*>(*iter)->get_content();
else
if(child->get_name()=="author")
{
-
+
xmlpp::Element::NodeList list = child->get_children();
-
+
// If we don't have any description, warn
if(list.empty())
warning(child,_("blank \"author\" entitity"));
-
+
string tmp;
for(xmlpp::Element::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
if(dynamic_cast<xmlpp::TextNode*>(*iter))tmp+=dynamic_cast<xmlpp::TextNode*>(*iter)->get_content();
if(canvas->value_node_list().placeholder_count())
{
- error(element,strprintf(_("Canvas %s has undefined ValueNodes"),canvas->get_id().c_str()));
+ error(element,strprintf(_("Canvas %s has undefined ValueNodes"),canvas->get_id().c_str()));
}
return canvas;
const ValueNodeList& value_node_list(canvas->value_node_list());
-
+
again:
ValueNodeList::const_iterator iter;
for(iter=value_node_list.begin();iter!=value_node_list.end();++iter)
goto again;
}
}
-
+
return canvas;
}
}
void set_path(const synfig::String& x) { path=x; }
const synfig::String& get_path()const { return path; }
-
+
//! \todo writeme
Canvas::Handle parse_from_file(const String &filename);
bool ret=true;
CHECK_EXPIRE_TIME();
-
+
if(version!=SYNFIG_LIBRARY_VERSION)
{
synfig::error(_("API Version mismatch (LIB:%d, PROG:%d)"),SYNFIG_LIBRARY_VERSION,version);
synfig::error(_("Size of Layer mismatch (app:%d, lib:%d)"),layer_size,sizeof(Layer));
ret=false;
}
-
+
return ret;
}
String modulename;
getline(file,modulename);
if(!modulename.empty() && find(modules_to_load.begin(),modules_to_load.end(),modulename)==modules_to_load.end())
- modules_to_load.push_back(modulename);
+ modules_to_load.push_back(modulename);
}
}
-
-
+
+
return true;
}
synfig_ref_count_.reset();
ref_count_=synfig_ref_count_;
-
+
// Add initialization after this point
#ifdef _DEBUG
std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#endif
-
+
#if defined(HAVE_SIGNAL_H) && defined(SIGPIPE)
signal(SIGPIPE, broken_pipe_signal);
#endif
-
+
//_config_search_path=new vector"string.h"();
-
+
// Init the subsystems
if(cb)cb->amount_complete(0, 100);
if(cb)cb->task(_("Starting Subsystem \"Modules\""));
Module::subsys_stop();
throw std::runtime_error(_("Unable to initialize subsystem \"Targets\""));
}
-
+
if(cb)cb->task(_("Starting Subsystem \"Importers\""));
if(!Importer::subsys_init())
{
Module::subsys_stop();
throw std::runtime_error(_("Unable to initialize subsystem \"ValueNodes\""));
}
-
+
// Load up the list importer
Importer::book()[String("lst")]=ListImporter::create;
-
-
- // Load up the modules
+
+
+ // Load up the modules
std::list<String> modules_to_load;
std::vector<String> locations;
-
+
if(!getenv("SYNFIG_MODULE_LIST"))
{
locations.push_back("standard");
{
locations.push_back(getenv("SYNFIG_MODULE_LIST"));
}
-/*
+/*
const char *locations[]=
{
"standard", //0
#endif
};
*/
-
+
for(i=0;i<locations.size();i++)
if(retrieve_modules_to_load(locations[i],modules_to_load))
if(cb)cb->task(strprintf(_("Loading modules from %s"),locations[i].c_str()));
-
+
std::list<String>::iterator iter;
-
+
for(i=0,iter=modules_to_load.begin();iter!=modules_to_load.end();++iter,i++)
{
Module::Register(*iter,cb);
if(cb)cb->amount_complete((i+1)*100,modules_to_load.size()*100);
}
-
+
// load_modules(cb);
-
+
CHECK_EXPIRE_TIME();
-
+
if(cb)cb->amount_complete(100, 100);
if(cb)cb->task(_("DONE"));
}
synfig::warning("%s: count()=%d",iter->first.c_str(), iter->second.count());
}
}
-
+
ValueNode::subsys_stop();
Importer::subsys_stop();
Target::subsys_stop();
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
/*! \class synfig::Main
** \brief \writeme
**
#ifndef SYNFIG_LTDL_NO_STATIC
//LTDL_SET_PRELOADED_SYMBOLS();
#endif
-
+
if(lt_dlinit())
{
error(_("Errors on lt_dlinit()"));
#endif
lt_dladdsearchdir("/usr/local/lib/synfig/modules");
lt_dladdsearchdir(".");
-#endif
+#endif
book_=new Book;
return true;
}
Module::subsys_stop()
{
delete book_;
-
+
#ifndef USE_CF_BUNDLES
lt_dlexit();
#endif
module=lt_dlopenext((string("lib")+module_name).c_str());
if(!module)module=lt_dlopenext(module_name.c_str());
-
+
if(!module)
{
if(callback)callback->warning(strprintf(_("Unable to find module \"%s\" (%s)"),module_name.c_str(),lt_dlerror()));
}
if(callback)callback->task(strprintf(_("Found module \"%s\""),module_name.c_str()));
-
+
Module::constructor_type constructor=NULL;
Handle mod;
// if(callback)callback->task(string("looking for -> lib")+module_name+"_LTX_new_instance()");
constructor=(Module::constructor_type )lt_dlsym(module,(string("_")+module_name+"_LTX_new_instance").c_str());
}
-
+
if(constructor)
{
// if(callback)callback->task(strprintf("Executing callback for \"%s\"",module_name.c_str()));
}
if(callback)callback->task(strprintf(_("Success for \"%s\""),module_name.c_str()));
-
+
#endif
return false;
}
/* === M A C R O S ========================================================= */
//! Marks the start of a module description
-#define MODULE_DESC_BEGIN(x) struct x##_modclass : public synfig::Module { x##_modclass(synfig::ProgressCallback *callback=NULL);
+#define MODULE_DESC_BEGIN(x) struct x##_modclass : public synfig::Module { x##_modclass(synfig::ProgressCallback *callback=NULL);
//! Sets the localized name of the module
#define MODULE_NAME(x) virtual const char * Name() { return x; }
synfig::Module* _##x##_LTX_new_instance(synfig::ProgressCallback *cb) \
{ if(SYNFIG_CHECK_VERSION()){x##_modclass *mod=new x##_modclass(cb); mod->constructor_(cb); return mod; }\
if(cb)cb->error(#x": Unable to load module due to version mismatch."); return NULL; } \
- }; x##_modclass::x##_modclass(synfig::ProgressCallback *cb) {
+ }; x##_modclass::x##_modclass(synfig::ProgressCallback *cb) {
#else
//! Marks the start of a module's inventory
#define MODULE_INVENTORY_BEGIN(x) extern "C" { \
synfig::Module* x##_LTX_new_instance(synfig::ProgressCallback *cb) \
{ if(SYNFIG_CHECK_VERSION()){x##_modclass *mod=new x##_modclass(cb); mod->constructor_(cb); return mod; }\
if(cb)cb->error(#x": Unable to load module due to version mismatch."); return NULL; } \
- }; x##_modclass::x##_modclass(synfig::ProgressCallback *cb) {
+ }; x##_modclass::x##_modclass(synfig::ProgressCallback *cb) {
#endif
//! Marks the start of the layers in the module's inventory
public:
bool constructor_(synfig::ProgressCallback *cb) { return true; }
virtual void destructor_() { }
-
+
typedef etl::handle<Module> Handle;
typedef etl::loose_handle<Module> LooseHandle;
typedef etl::handle<const Module> ConstHandle;
-
+
public:
typedef Module*(*constructor_type)(ProgressCallback *);
typedef std::map<String, Handle > Book;
static void Register(Handle mod);
static bool Register(const String &module_name, ProgressCallback *cb=NULL);
static inline void Register(Module *mod) { Register(Handle(mod)); }
-
+
virtual const char * Name() { return " "; }
virtual const char * Desc() { return " "; }
virtual const char * Author() { return " "; }
pthread_mutex_init(mtx_ptr,&attr);
pthread_mutexattr_destroy(&attr);
-
+
blackbox=mtx_ptr;
}
RWLock::RWLock()
{
pthread_rwlock_t*const rwlock_ptr(new pthread_rwlock_t);
-
+
pthread_rwlock_init(rwlock_ptr, NULL);
-
+
blackbox=rwlock_ptr;
}
pthread_rwlock_t*const rwlock_ptr(static_cast<pthread_rwlock_t*>(blackbox));
pthread_rwlock_destroy(rwlock_ptr);
-
+
delete rwlock_ptr;
}
protected:
void* blackbox;
-
+
public:
-
+
class Lock
{
Mutex& mutex;
Lock(Mutex& x):mutex(x) { mutex.lock(); }
~Lock() { mutex.unlock(); }
};
-
+
Mutex();
~Mutex();
-
+
void lock();
void unlock();
bool try_lock();
bool is_locked();
-
+
private:
//! Non-copyable
Mutex(const Mutex&);
-
+
//! Non-assignable
void operator=(const Mutex&);
};
class RWLock
{
void* blackbox;
-
+
public:
-
+
class ReaderLock
{
RWLock& rw_lock;
WriterLock(RWLock& x):rw_lock(x) { rw_lock.writer_lock(); }
~WriterLock() { rw_lock.writer_unlock(); }
};
-
+
RWLock();
~RWLock();
if(get_guid()==x.get_guid())
return;
set_guid(get_guid()^x.get_guid());
-
+
if(get_after()==INTERPOLATION_NIL)
set_after(x.get_after());
if(get_before()==INTERPOLATION_NIL)
set_before(x.get_before());
-
+
if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
set_after(INTERPOLATION_UNDEFINED);
if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
- set_before(INTERPOLATION_UNDEFINED);
+ set_before(INTERPOLATION_UNDEFINED);
}
TimePointSet::iterator
guid_.make_unique();
assert(guid_);
assert(!global_node_map().count(guid_));
- global_node_map()[guid_]=this;
+ global_node_map()[guid_]=this;
#endif
}
const_cast<GUID&>(guid_).make_unique();
assert(guid_);
assert(!global_node_map().count(guid_));
- global_node_map()[guid_]=const_cast<Node*>(this);
+ global_node_map()[guid_]=const_cast<Node*>(this);
}
#endif
-
+
return guid_;
}
{
guid_=x;
assert(!global_node_map().count(guid_));
- global_node_map()[guid_]=this;
+ global_node_map()[guid_]=this;
}
else
#endif
get_times_vfunc(times);
bchanged = false;
}
-
+
//set the output set...
return times;
}
void set_time(const Time& x) { time=x; }
void set_before(Interpolation x) { before=x; }
void set_after(Interpolation x) { after=x; }
-
+
void absorb(const TimePoint& x);
}; // END of class TimePoint
{ for(;begin!=end;++begin) insert(*begin); }
}; // END of class TimePointSet
-
+
class Node : public etl::rshared_object
{
/*
-- ** -- T Y P E S -----------------------------------------------------------
*/
-public:
-
+public:
+
//! \writeme
typedef TimePointSet time_set;
//! \writeme
mutable RWLock rw_lock_;
-
+
//! \writeme
bool deleting_;
*/
private:
-
+
sigc::signal<void> signal_changed_;
//! GUID Changed
/*! \note The second parameter is the *OLD* guid! */
- sigc::signal<void,GUID> signal_guid_changed_;
+ sigc::signal<void,GUID> signal_guid_changed_;
//! Deleted
- sigc::signal<void> signal_deleted_;
+ sigc::signal<void> signal_deleted_;
/*
-- ** -- S I G N A L I N T E R F A C E -------------------------------------
/*
-- ** -- M E M B E R F U N C T I O N S -------------------------------------
*/
-
+
public:
void changed();
void set_guid(const GUID& x);
int get_time_last_changed()const;
-
+
void add_child(Node*x);
void remove_child(Node*x);
int parent_count()const;
-
+
const time_set &get_times() const;
RWLock& get_rw_lock()const { return rw_lock_; }
-
+
protected:
-
+
void begin_delete();
-
+
/*
-- ** -- V I R T U A L F U N C T I O N S -----------------------------------
*/
virtual void on_guid_changed(GUID guid);
- /*! Function to be overloaded that fills
+ /*! Function to be overloaded that fills
*/
virtual void get_times_vfunc(time_set &set) const = 0;
-};
+};
synfig::Node* find_node(const synfig::GUID& guid);
Palette::Palette(const Surface& surface, int max_colors):
name_(_("Surface Palette"))
-{
+{
max_colors-=2;
for(int i=0;(signed)size()<(max_colors-1) && i<max_colors*16;++i) {
int x=rand()%surface.get_w();
float dist;
Color color(surface[y][x]);
-
+
if(empty())
{
push_back(color);
iter->add(color);
continue;
}
-
+
/*if(size()>=max_colors)
{
iterator iterlight(find_light());
find_closest(light.color)->add(light.color,light.weight);
}
*/
-
+
push_back(color);
- continue;
+ continue;
}
/*
{
float dist;
Color color(surface[y][x]);
-
+
if(empty())
{
push_back(color);
iter->add(color);
continue;
}
-
-
+
+
push_back(color);
- continue;
+ continue;
}
sort(rbegin(),rend());
const float prep_y(powf(color.get_y(),2.2f)*color.get_a());
const float prep_u(color.get_u());
const float prep_v(color.get_v());
-
+
for(iter=begin();iter!=end();++iter)
{
const float diff_y(prep_y-powf(iter->color.get_y(),2.2f)*iter->color.get_a());
diff_y*diff_y*1.5f+
diff_a*diff_a+
- diff_u*diff_u+
+ diff_u*diff_u+
diff_v*diff_v
-
+
// cross product
/*abs(
- prep_u*iter->color.get_u()-
+ prep_u*iter->color.get_u()-
prep_v*iter->color.get_v()
)*/
);
}
if(dist)
*dist=best_dist;
-
+
return best_match;
}
iterator iter;
iterator best_match(begin());
-
+
for(iter=begin();iter!=end();++iter)
{
if(iter->weight>best_match->weight)
best_match=iter;
}
-
+
return best_match;
}
iterator iter;
iterator best_match(begin());
-
+
for(iter=begin();iter!=end();++iter)
{
if(iter->weight<best_match->weight)
best_match=iter;
}
-
+
return best_match;
}
const_iterator iter;
std::ofstream file(filename.c_str());
-
+
if(!file)
throw strprintf(_("Unable to open %s for write"),filename.c_str());
-
+
file<<PALETTE_FILE_COOKIE<<endl;
- file<<name_<<endl;
+ file<<name_<<endl;
for(iter=begin();iter!=end();++iter)
{
file<<iter->name<<endl;
<<iter->color.get_g()<<endl
<<iter->color.get_b()<<endl
<<iter->color.get_a()<<endl;
-
+
}
}
Palette::load_from_file(const synfig::String& filename)
{
std::ifstream file(filename.c_str());
-
+
if(!file)
throw strprintf(_("Unable to open %s for read"),filename.c_str());
-
+
Palette ret;
String line;
-
+
getline(file,line);
if(line!=PALETTE_FILE_COOKIE)
throw strprintf(_("%s does not appear to be a palette file"),filename.c_str());
getline(file,ret.name_);
-
+
while(!file.eof())
{
PaletteItem item;
getline(file,line);
if(!file.eof())break;
item.color.set_a(atof(line.c_str()));
-
+
ret.push_back(item);
}
-
+
return ret;
}
namespace synfig {
class Surface;
-
+
struct PaletteItem
{
Color color;
String name;
int weight;
-
+
PaletteItem():weight(1) { }
PaletteItem(const Color& color, const String& name, int weight=1):
PaletteItem(const Color& color, int weight=1):
color(color),weight(weight) { }
-
+
void add(const Color& x, int weight=1);
-
+
bool operator<(const PaletteItem& rhs)const { return weight<rhs.weight; }
}; // END of struct PaletteItem
class Palette : public std::vector<PaletteItem>
{
String name_;
-
+
public:
Palette();
Palette(const String& name_);
-
+
/*! Generates a palette for the given
** surface
*/
const_iterator find_closest(const Color& color, float* dist=0)const;
iterator find_heavy();
-
+
iterator find_light();
static Palette grayscale(int steps=16);
namespace synfig {
class ValueBase;
-
+
/*! \class ParamDesc
** \brief Parameter Description Class
** \todo writeme
{
}
};
-
+
/*
-- ** -- D A T A -------------------------------------------------------------
*/
bool animation_only_;
std::list<EnumData> enum_list_;
-
+
/*
-- ** -- C O N S T R U C T O R S ---------------------------------------------
*/
//! \writeme
const std::list<EnumData> &get_enum_list()const { return enum_list_; }
-
+
//! Sets the localized name of the parameter.
ParamDesc &set_local_name(const String &n) { local_name_=n; return *this; }
//! Returns the flag regarding duck visibility
bool get_invisible_duck() { return invisible_duck_; }
-
+
//! \writeme
ParamDesc &set_animation_only(bool x=true) { animation_only_=x; return *this; }
//! \writeme
bool get_animation_only() { return animation_only_; }
-
+
//! Sets which parameter is to be used as the origin when the user edits visually.
ParamDesc &set_origin(const String &h) { origin_=h; return *this; }
//! Returns \c true if the layer is hidden, \c false otherwise.
bool get_hidden()const { return hidden_; }
-
-
+
+
ParamDesc& set_is_distance(bool x=true) { is_distance_=x; return *this;}
bool get_is_distance()const { return is_distance_; }
}; // END of class ParamDesc
*/
/* Explanation:
-
+
A polynomial can be represented like so:
Pn(x) = (x - x1)(x - x2)...(x - xn) where xi = complex roots
We can get the following:
- ln|Pn(x)| = ln|x - x1| + ln|x - x2| + ... + ln|x - xn|
-
+ ln|Pn(x)| = ln|x - x1| + ln|x - x2| + ... + ln|x - xn|
+
G := d ln|Pn(x)| / dx =
+1/(x-x1) + 1/(x-x2) + ... + 1/(x-xn)
-
+
and
-
+
H := - d2 ln|Pn(x)| / d2x =
+1/(x-x1)^2 + 1/(x-x2)^2 + ... + 1/(x-xn)^2
-
+
which gives
H = [Pn'/Pn]^2 - Pn''/Pn
-
- Laguerre's formula guesses that the root we are seeking x1 is located
+
+ Laguerre's formula guesses that the root we are seeking x1 is located
some distance a from our current guess x, and all the other roots are
located at distance b.
-
+
Using this:
-
+
1/a + (n-1)/b = G
-
- and
-
+
+ and
+
1/a^2 + (n-1)/b^2 = H
which yields this solution for a:
-
+
a = n / G +- sqrt( (n-1)(nH - G^2) )
-
+
where +- is determined by which ever yields the largest magnitude for the denominator.
a can easily be complex since the factor inside the square-root can be negative.
-
+
This method iterates (x=x-a) until a is sufficiently small.
*/
/* Given the degree m and the m+1 complex coefficients a[0..m] of the polynomial sum(i=0,m){a[i]x^i},
and given a complex value x, this routine improves x by laguerre's method until it converges,
-within the acheivable roundoff limit, to a root of teh given polynomial. The number of iterations taken
+within the acheivable roundoff limit, to a root of teh given polynomial. The number of iterations taken
is returned as its.
*/
void laguer(Complex a[], int m, Complex *x, int *its)
int iter,j;
float abx, abp, abm, err;
Complex dx,x1,b,d,f,g,h,sq,gp,gm,g2;
-
+
//Fractions used to break a limit cycle
static float frac[MR+1] = {0.0,0.5,0.25,0.75,0.13,0.38,0.62,0.88,1.0};
-
+
for(iter = 1; iter <= MAXIT; ++iter)
{
*its = iter; //number of iterations so far
-
+
b = a[m]; //the highest coefficient
err = abs(b); //its magnitude
-
+
d = f = Complex(0,0); //clear variables for use
abx = abs(*x); //the magnitude of the current root
-
+
//Efficent computation of the polynomial and it's first 2 derivatives
for(j = m-1; j >= 0; --j)
{
f = (*x)*f + d;
d = (*x)*d + b;
b = (*x)*b + a[j];
-
+
err = abs(b) + abx*err;
}
-
+
//Estimate the roundoff error in evaluation polynomial
err *= EPSS;
-
+
//Are we on the root?
if(abs(b) < err)
{
return;
}
-
+
//General case: use Laguerre's formula
//a = n / G +- sqrt( (n-1)(nH - G^2) )
//x = x - a
-
+
g = d / b; //get G
g2 = g * g; //for the sqrt calc
-
+
h = g2 - 2.0f * (f / b); //get H
-
+
sq = pow( (float)(m-1) * ((float)m*h - g2), 0.5f ); //get the sqrt
-
+
//get the denominator
gp = g + sq;
gm = g - sq;
abp = abs(gp);
- abm = abs(gm);
-
+ abm = abs(gm);
+
//get the denominator with the highest magnitude
if(abp < abm)
{
abp = abm;
gp = gm;
}
-
+
//if the denominator is positive do one thing, otherwise do the other
dx = (abp > 0.0) ? (float)m / gp : polar((1+abx),(float)iter);
x1 = *x - dx;
-
+
//Have we converged?
if( *x == x1 )
{
return;
}
-
+
//Every so often take a fractional step, to break any limit cycle (itself a rare occurrence).
if( iter % MT )
{
*x = *x - (frac[iter/MT]*dx);
}
}
-
+
//very unusual - can occur only for complex roots. Try a different starting guess for the root.
//nrerror("too many iterations in laguer");
return;
int i,its,j,jj;
Complex x,b,c;
int m = coefs.size()-1;
-
+
//make sure roots is big enough
roots.resize(m);
-
+
if(workcoefs.size() < MAXM) workcoefs.resize(MAXM);
//Copy the coefficients for successive deflation
{
workcoefs[j] = coefs[j];
}
-
+
//Loop over each root to be found
for(j = m-1; j >= 0; --j)
{
//Start at 0 to favor convergence to smallest remaining root, and find the root
- x = Complex(0,0);
+ x = Complex(0,0);
laguer(&workcoefs[0],j+1,&x,&its); //must add 1 to get the degree
-
+
//if it is close enough to a real root, then make it so
if(abs(x.imag()) <= 2.0*EPS*abs(x.real()))
{
x = Complex(x.real());
}
-
+
roots[j] = x;
-
+
//forward deflation
-
+
//the degree is j+1 since j(0,m-1)
b = workcoefs[j+1];
for(jj = j; jj >= 0; --jj)
b = x*b + c;
}
}
-
+
//Polish the roots using the undeflated coefficients
if(polish)
{
laguer(&coefs[0],m,&roots[j],&its);
}
}
-
+
//Sort roots by their real parts by straight insertion
for(j = 1; j < m; ++j)
{
/* === C L A S S E S & S T R U C T S ======================================= */
template < typename T = float, typename F = float >
class Polynomial : public std::vector<T> //a0 + a1x + a2x^2 + ... + anx^n
-{
+{
public:
-
+
//Will maintain all lower constants
void degree(unsigned int d, const T & def = (T)0) { resize(d+1,def); }
unsigned int degree()const { return size() - 1; }
-
+
const Polynomial & operator+=(const Polynomial &p)
{
if(p.size() > size())
resize(p.size(), (T)0);
-
+
for(int i = 0; i < p.size(); ++i)
{
(*this)[i] += p[i];
}
return *this;
}
-
+
const Polynomial & operator-=(const Polynomial &p)
{
if(p.size() > size())
resize(p.size(), (T)0);
-
+
for(int i = 0; i < p.size(); ++i)
{
(*this)[i] -= p[i];
}
return *this;
}
-
+
const Polynomial & operator*=(const Polynomial &p)
{
if(p.size() < 1)
resize(0);
return *this;
}
-
+
unsigned int i,j;
std::vector<T> nc(*this);
-
+
//in place for constant stuff
for(i = 0; i < nc.size(); ++i)
{
(*this)[i] *= p[0];
}
-
+
if(p.size() < 2) return *this;
-
- resize(size() + p.degree());
+
+ resize(size() + p.degree());
for(int i = 0; i < nc.size(); ++i)
{
for(int j = 1; j < p.size(); ++j)
nc[i+j] += nc[i]*p[j];
}
}
-
+
return *this;
- }
+ }
};
class RootFinder
{
std::vector< std::complex<float> > workcoefs;
int its;
-
+
public:
std::vector< std::complex<float> > coefs; //the number of coefficients determines the degree of polynomial
* class Object
{
public:
-
+
sigc::signal_
bool find_protocol(Protocol& proto)
{
-
+
}
};
*/
{
public:
class Type;
-
+
}; // END of class Protocol
class Protocol::Type
Rect(const Point& min, const Point& max) { set_point(min); expand(max); }
Rect(const value_type &x1,const value_type &y1) { set_point(x1,y1); }
-
+
Rect(const value_type &x1,const value_type &y1,
const value_type &x2,const value_type &y2)
{
set_point(x1,y1);
expand(x2,y2);
}
-
+
void set_point(const Point& max) { set_point(max[0],max[1]); }
-
+
Rect& expand(const Point& max) { expand(max[0],max[1]); return *this; }
Rect& expand(const Real& r) { minx-=r; miny-=r; maxx+=r; maxy+=r; return *this; }
Rect& expand_x(const Real& r) { minx-=r; maxx+=r; return *this; }
Rect& expand_y(const Real& r) { miny-=r; maxy+=r; return *this; }
-
+
Rect& set(const Point& min,const Point& max) { set(min[0],min[1],max[0],max[1]); return *this; }
-
+
Point get_min()const { return Point(minx,miny); }
Point get_max()const { return Point(maxx,maxy); }
-
+
bool is_inside(const Point& x) { return x[0]>minx && x[0]<maxx && x[1]>miny && x[1]<maxy; }
-
+
Real area()const
{
return (maxx-minx)*(maxy-miny);
}
-
+
// Operators
-
+
Rect& operator+=(const Vector& rhs)
{
minx+=rhs[0]; miny+=rhs[1];
RendDesc &
RendDesc::set_interlaced(bool x)
-{ interlaced=x; return *this; }
+{ interlaced=x; return *this; }
//! Return the status of the clamp flag
const bool &
//! Set the clamp flag
RendDesc &
RendDesc::set_clamp(bool x)
-{ clamp=x; return *this; }
+{ clamp=x; return *this; }
//! Set constraint flags
RendDesc &
/*
const Gamma &
RendDesc::get_gamma()const
-{ return gamma; }
+{ return gamma; }
RendDesc &
RendDesc::set_gamma(const Gamma &x)
Vector new_size(x-br_);
new_size[0]=abs(new_size[0]);
new_size[1]=abs(new_size[1]);
-
+
Vector old_size(tl_-br_);
old_size[0]=abs(old_size[0]);
old_size[1]=abs(old_size[1]);
-
+
if(new_size[0]!=old_size[0])
w_=round_to_int(new_size[0]*w_/old_size[0]);
-
+
if(new_size[1]!=old_size[1])
h_=round_to_int(new_size[1]*h_/old_size[1]);
}
-
+
tl_=x; return *this;
}
Vector new_size(x-tl_);
new_size[0]=abs(new_size[0]);
new_size[1]=abs(new_size[1]);
-
+
Vector old_size(tl_-br_);
old_size[0]=abs(old_size[0]);
old_size[1]=abs(old_size[1]);
-
+
if(new_size[0]!=old_size[0])
w_=round_to_int(new_size[0]*w_/old_size[0]);
-
+
if(new_size[1]!=old_size[1])
h_=round_to_int(new_size[1]*h_/old_size[1]);
}
{
const Real pw(get_pw());
const Real ph(get_ph());
-
+
tl_[0]+=pw*x;
tl_[1]+=ph*y;
w_=w;
h_=h;
-
+
return *this;
}
PX_AREA=(1<<1),
PX_W=(1<<2),
PX_H=(1<<3),
-
+
IM_ASPECT=(1<<4),
IM_SPAN=(1<<5),
IM_W=(1<<6),
IM_H=(1<<7),
IM_ZOOMIN=(1<<8),
IM_ZOOMOUT=(1<<9),
-
+
LINK_PX_ASPECT=(1<<10),
LINK_PX_AREA=(1<<11),
LINK_IM_ASPECT=(1<<12),
LINK_IM_SPAN=(1<<13),
LINK_IM_CENTER=(1<<14)
};
-
+
private:
int w_,h_;
Real x_res;
float frame_rate;
Time time_begin, time_end;
-
+
public:
enum
time_begin (0),
time_end (0)
{ }
-
+
//! \writeme
RendDesc &apply(const RendDesc &x);
-
+
//! \writeme
const Color &get_bg_color()const;
//! Sets the horizontal resolution (in dots per meter)
RendDesc &set_x_res(Real x);
-
+
//! Returns the vertical resolution (in dots per meter)
Real get_y_res()const;
//! Set the index of the first frame
RendDesc &set_frame_start(int x);
-
+
//! Return the index of the last frame
int get_frame_end()const;
-
+
//! Set the index of the last frame
RendDesc &set_frame_end(int x);
//! Return the starting time of the animation
const Time get_time_start()const;
-
+
//! Set the time that the animation will start
RendDesc &set_time_start(Time x);
//! Return the end time of the animation
const Time get_time_end()const;
-
+
//! Set the time that the animation will end
RendDesc &set_time_end(Time x);
//! Return the frame rate (frames-per-second)
const float &get_frame_rate()const;
-
+
//! Set the frame rate (frames-per-second)
RendDesc &set_frame_rate(float x);
//! Return the status of the interlaced flag
const bool &get_interlaced()const;
-
+
//! Set the interlace flag
RendDesc &set_interlaced(bool x);
//! Return the status of the clamp flag
const bool &get_clamp()const;
-
+
//! Set the clamp flag
RendDesc &set_clamp(bool x);
//! Set constraint flags
RendDesc &set_flags(const int &x);
-
+
//! Clear constraint flags
RendDesc &clear_flags();
//! Return the aspect ratio of the entire image
Point::value_type get_image_aspect()const;
-
+
//! Return the antialias amount
const int &get_antialias()const;
RendDesc &set_focus(const Point &x);
const Point &get_tl()const;
-
+
RendDesc &set_tl(const Point &x);
const Point &get_br()const;
-
+
RendDesc &set_br(const Point &x);
-
+
Rect get_rect()const { return Rect(get_tl(),get_br()); }
RendDesc &set_viewport(const Point &__tl, const Point &__br);
-
+
RendDesc &set_viewport(Vector::value_type a,Vector::value_type b,Vector::value_type c,Vector::value_type d);
//! Returns the width of one pixel
bool
no_clamp=!desc.get_clamp();
-
+
int
w(desc.get_w()),
h(desc.get_h()),
a(desc.get_antialias());
-
+
Point
tl(desc.get_tl()),
br(desc.get_br());
-
+
//Gamma
// gamma(desc.get_gamma());
Color::value_type
pool; // Alpha pool (for correct alpha antialiasing)
-
+
// Calculate the number of channels
//chan=channels(desc.get_pixel_format());
-
+
// Calculate the distance between pixels
du=(br[0]-tl[0])/(Point::value_type)w;
dv=(br[1]-tl[1])/(Point::value_type)h;
//sv=tl[1]-(dv-dsv)/(Point::value_type)2.0;
su=tl[0];
sv=tl[1];
-
+
surface.set_wh(desc.get_w(),desc.get_h());
assert(surface);
-
+
// Loop through all horizontal lines
for(y=0,v=sv;y<h;y++,v+=dv)
{
Color *colordata=surface[y];
assert(colordata);
-
+
// If we have a callback that we need
// to report to, do so now.
if(callback)
c/=pool;
}
}
-
+
// Give the callback one more last call,
// this time with the full height as the
// current line
bool
no_clamp=!desc.get_clamp();
-
+
int
w(desc.get_w()),
h(desc.get_h()),
a(desc.get_antialias());
-
+
Point
tl(desc.get_tl()),
br(desc.get_br());
-
+
//Gamma
// gamma(desc.get_gamma());
pool; // Alpha pool (for correct alpha antialiasing)
assert(target);
-
+
// If we do not have a a target then bail
if(!target)
return false;
-
+
// Calculate the number of channels
//chan=channels(desc.get_pixel_format());
-
+
// Calculate the distance between pixels
du=(br[0]-tl[0])/(Point::value_type)w;
dv=(br[1]-tl[1])/(Point::value_type)h;
// Mark the start of a new frame.
if(!target->start_frame(callback))
return false;
-
+
// Loop through all horizontal lines
for(y=0,v=sv;y<h;y++,v+=dv)
{
else throw(string(_("Target panic")));
return false;
}
-
+
// If we have a callback that we need
// to report to, do so now.
if(callback)
return false;
}
}
-
+
// Finish up the target's frame
target->end_frame();
}
}
} *render_thread;
-
+
int i, mythread=-1;
-
+
Point::value_type
u,v, // Current location in image
su,sv, // Starting locations
bool
no_clamp=!desc.get_clamp();
-
+
int
w(desc.get_w()),
h(desc.get_h()),
a(desc.get_antialias());
-
+
Point
tl(desc.get_tl()),
br(desc.get_br());
-
+
int
x,y, // Current location on output bitmap
x2,y2; // Subpixel counters
pool; // Alpha pool (for correct alpha antialiasing)
assert(target);
-
+
// If we do not have a a target then bail
if(!target)
return false;
-
+
// Calculate the distance between pixels
du=(br[0]-tl[0])/(Point::value_type)w;
dv=(br[1]-tl[1])/(Point::value_type)h;
sv=tl[1]-(dv-dsv)/(Point::value_type)2.0;
render_thread=new _render_thread[threads];
-
+
// Start the forks
for(i=0;i<threads;i++)
{
}
render_thread[i].pid=pid;
}
-
+
// Mark the start of a new frame.
if(!target->start_frame(callback))
return false;
else throw(string(_("Target panic")));
return false;
}
-
+
// If we have a callback that we need
// to report to, do so now.
if(callback)
delete [] render_thread;
return false;
}
-
+
read(render_thread[y%threads].pipe_read,colordata,w*sizeof(Color));
-
+
// Send the buffer to the render target.
// If anything goes wrong, cleanup and bail.
if(!target->end_scanline())
// current line
if(callback)
callback->amount_complete(h,h);
-
+
delete [] render_thread;
return true;
renderthread:
-
+
// Change the random seed, so that each thread has a different one
srand(mythread*20+threads+time(0));
-
+
Color *buffer(new Color[w]);
// Loop through all horizontal lines
// Set the current pixel pointer
// to the start of the line
Color* colordata(buffer);
-
+
// Loop through every pixel in row
for(x=0,u=su;x<w;x++,u+=du)
{
if(pool)
c/=pool;
}
-
+
// Send the buffer to the primary thread.
write(render_thread[mythread].pipe_write,buffer,w*sizeof(Color));
}
-
+
delete [] buffer;
-
+
_exit(0);
- return false;
+ return false;
#else
return render(context, target, desc, callback);
-#endif
+#endif
}
if(bline_point.get_split_tangent_flag())
encode_vector(root->add_child("t2")->add_child("vector"),bline_point.get_tangent2());
-
+
encode_real(root->add_child("width")->add_child("real"),bline_point.get_width());
encode_real(root->add_child("origin")->add_child("real"),bline_point.get_origin());
return root;
xmlpp::Element* encode_gradient(xmlpp::Element* root,Gradient x)
{
root->set_name("gradient");
-
+
Gradient::const_iterator iter;
x.sort();
for(iter=x.begin();iter!=x.end();iter++)
xmlpp::Element* encode_list(xmlpp::Element* root,std::list<ValueBase> list, Canvas::ConstHandle canvas=0)
{
root->set_name("list");
-
+
while(!list.empty())
{
encode_value(root->add_child("value"),list.front(),canvas);
waypoint_node->set_attribute("use",iter->get_value_node()->get_relative_id(canvas));
else
encode_value_node(waypoint_node->add_child("value_node"),iter->get_value_node(),canvas);
-
+
switch(iter->get_before())
{
case INTERPOLATION_HALT:
{
assert(value_node);
const float fps(canvas?canvas->rend_desc().get_frame_rate():0);
-
+
root->set_name(value_node->get_name());
root->set_attribute("type",ValueBase::type_name(value_node->get_contained_type()));
vector<ValueNode_DynamicList::ListEntry>::const_iterator iter;
ValueNode_BLine::ConstHandle bline_value_node(ValueNode_BLine::ConstHandle::cast_dynamic(value_node));
-
+
if(bline_value_node)
{
if(bline_value_node->get_loop())
else
root->set_attribute("loop","false");
}
-
+
for(iter=value_node->list.begin();iter!=value_node->list.end();++iter)
{
xmlpp::Element *entry_node=root->add_child("entry");
const ActivepointList& timing_info(iter->timing_info);
ActivepointList::const_iterator entry_iter;
-
+
for(entry_iter=timing_info.begin();entry_iter!=timing_info.end();++entry_iter)
if(entry_iter->state==true)
{
if(entry_iter->priority)
begin_sequence+=strprintf("p%d ",entry_iter->priority);
begin_sequence+=entry_iter->time.get_string(fps)+", ";
- }
+ }
else
{
if(entry_iter->priority)
end_sequence+=strprintf("p%d ",entry_iter->priority);
end_sequence+=entry_iter->time.get_string(fps)+", ";
}
-
+
// If this is just a plane-jane vanilla entry,
// then don't bother with begins and ends
if(end_sequence.empty() && begin_sequence=="SOT, ")
begin_sequence.clear();
-
+
if(!begin_sequence.empty())
{
// Remove the last ", " stuff
begin_sequence=String(begin_sequence.begin(),begin_sequence.end()-2);
// Add the attribute
- entry_node->set_attribute("on",begin_sequence);
- }
+ entry_node->set_attribute("on",begin_sequence);
+ }
if(!end_sequence.empty())
{
// Remove the last ", " stuff
end_sequence=String(end_sequence.begin(),end_sequence.end()-2);
// Add the attribute
- entry_node->set_attribute("off",end_sequence);
- }
+ entry_node->set_attribute("off",end_sequence);
+ }
}
}
if(value.get_type()==ValueBase::TYPE_CANVAS && !value.get(Canvas::LooseHandle())->is_inline())
{
Canvas::Handle child(value.get(Canvas::LooseHandle()));
-
+
if(!value.get(Canvas::Handle()))
continue;
xmlpp::Element *node=root->add_child("param");
node->set_attribute("name",iter->get_name());
encode_value(node->add_child("value"),value,layer->get_canvas().constant());
- }
+ }
}
assert(canvas);
const RendDesc &rend_desc=canvas->rend_desc();
root->set_name("canvas");
-
+
if(canvas->is_root())
root->set_attribute("version","0.1");
if(!canvas->parent() || canvas->parent()->rend_desc().get_time_end()!=canvas->rend_desc().get_time_end())
root->set_attribute("end-time",rend_desc.get_time_end().get_string(rend_desc.get_frame_rate()));
-
+
if(!canvas->is_inline())
{
root->set_attribute("bgcolor",strprintf(VIEW_BOX_FORMAT,
for(KeyframeList::const_iterator iter=canvas->keyframe_list().begin();iter!=canvas->keyframe_list().end();++iter)
encode_keyframe(root->add_child("keyframe"),*iter,canvas->rend_desc().get_frame_rate());
}
-
+
// Output the <defs> section
if(!canvas->is_inline() && !canvas->value_node_list().empty() || !canvas->children().empty())
{
{
encode_canvas(node->add_child("canvas"),*iter);
}
- }
+ }
Canvas::const_reverse_iterator iter;
for(iter=canvas->rbegin();iter!=canvas->rend();++iter)
- encode_layer(root->add_child("layer"),*iter);
+ encode_layer(root->add_child("layer"),*iter);
return root;
}
{
assert(canvas);
xmlpp::Document document;
-
+
encode_canvas(document.create_root_node("canvas"),canvas);
-
+
document.write_to_file_formatted(tmp_filename);
}
catch(...) { synfig::error("synfig::save_canvas(): Caught unknown exception"); return false; }
-
-
+
+
#ifdef _WIN32
// On Win32 platforms, rename() has bad behavior. work around it.
char old_file[80]="sif.XXXXXXXX";
mktemp(old_file);
- rename(filename.c_str(),old_file);
+ rename(filename.c_str(),old_file);
if(rename(tmp_filename.c_str(),filename.c_str())!=0)
{
rename(old_file,tmp_filename.c_str());
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
/*! \struct Segment
** \todo writeme
*/
{
void operator()(FILE* x)const { if(x!=stdout && x!=stdin) fclose(x); }
};
-
+
typedef etl::smart_ptr<FILE,_FILE_deleter> SmartFILE;
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
virtual ~target2surface();
virtual bool set_rend_desc(synfig::RendDesc *newdesc);
-
+
virtual bool start_frame(synfig::ProgressCallback *cb);
-
+
virtual void end_frame();
virtual Color * start_scanline(int scanline);
desc=*newdesc;
return synfig::Target_Scanline::set_rend_desc(newdesc);
}
-
+
bool
-target2surface::start_frame(synfig::ProgressCallback *cb)
-{
+target2surface::start_frame(synfig::ProgressCallback *cb)
+{
if(surface->get_w() != desc.get_w() || surface->get_h() != desc.get_h())
{
surface->set_wh(desc.get_w(),desc.get_h());
}
- return true;
+ return true;
}
-
+
void
target2surface::end_frame()
{
return;
}
-
+
Color *
target2surface::start_scanline(int scanline)
{
if(x<0)
{
w+=x; //decrease
- x=0;
+ x=0;
}
-
+
if(y<0)
{
h+=y; //decrease
- y=0;
+ y=0;
}
-
+
//clip width against dest width
w = min((long)w,(long)(pen.end_x()-pen.x()));
h = min((long)h,(long)(pen.end_y()-pen.y()));
-
+
//clip width against src width
w = min(w,get_w()-x);
h = min(h,get_h()-y);
if(w<=0 || h<=0)
return;
-
+
for(int i=0;i<h;i++)
{
char* src(static_cast<char*>(static_cast<void*>(operator[](y)+x))+i*get_w()*sizeof(Color));
}
return;
}
-
-#ifdef HAS_VIMAGE
+
+#ifdef HAS_VIMAGE
if( pen.get_blend_method()==Color::BLEND_COMPOSITE && fabs(alpha-1.0f)<epsilon )
{
if(x>=get_w() || y>=get_w())
{
//u-=x; //increase
w+=x; //decrease
- x=0;
+ x=0;
}
-
+
if(y<0)
{
//v-=y; //increase
h+=y; //decrease
- y=0;
+ y=0;
}
-
+
//clip width against dest width
w = min(w,pen.end_x()-pen.x());
h = min(h,pen.end_y()-pen.y());
-
+
//clip width against src width
- w = min(w,get_w()-x);
- h = min(h,get_h()-y);
+ w = min(w,get_w()-x);
+ h = min(h,get_h()-y);
if(w<=0 || h<=0)
return;
vImage_Buffer top,bottom;
vImage_Buffer& dest(bottom);
-
+
top.data=static_cast<void*>(operator[](y)+x);
top.height=h;
top.width=w;
bottom.width=w;
//bottom.rowBytes=pen.get_width()*sizeof(Color); //! \fixme this should get the pitch!!
bottom.rowBytes=pen.get_pitch(); //! \fixme this should get the pitch!!
-
+
vImage_Error ret;
ret=vImageAlphaBlend_ARGBFFFF(&top,&bottom,&dest,kvImageNoFlags);
-
+
assert(ret!=kvImageNoError);
-
+
return;
}
#endif
{
if(!x.get_a())
return Color::alpha();
-
+
const float a(1.0f/x.get_a());
-
+
x.set_r(x.get_r()*a);
x.set_g(x.get_g()*a);
x.set_b(x.get_b()*a);
alpha_pen(const etl::alpha_pen< etl::generic_pen<Color, ColorAccumulator>, Color::value_type, _BlendFunc > &x):
etl::alpha_pen< etl::generic_pen<Color, ColorAccumulator>, Color::value_type, _BlendFunc >(x)
{ }
-
+
alpha_pen(const etl::generic_pen<Color, ColorAccumulator>& pen, const Color::value_type &a = 1, const _BlendFunc &func = _BlendFunc()):
etl::alpha_pen< etl::generic_pen<Color, ColorAccumulator>, Color::value_type, _BlendFunc >(pen,a,func)
{ }
float* data_;
float* origin_;
-
+
int w_,h_,stride_;
-
+
public:
RWLock rw_lock;
h_(0)
{
}
-
+
~ChannelData()
{
if(ref_count_.unique())
delete [] data_;
}
-
+
void set_wh(int w, int h)
{
w_=w;
h_=h;
stride_=w;
-
+
if(data_&&ref_count_.is_unique())
delete [] data_;
-
+
ref_count.make_unique();
data_=new float [w_*h_];
origin_=data_;
clear();
}
-
+
void crop(int x, int y, int w, int h)
{
origin_=origin+y*stride_+x;
w_=w;
h_=h;
}
-
+
int get_stride()const
{
return stride_;
}
-
+
void clear()
{
for(int i=0;i<h;i++)
void fill(float v)
{
float* ptr(get_data());
-
+
for(int y=0;y<h;y++,ptr+=stride_)
for(int i=0;i<w_;i++)
ptr[i]=v;
ref_count_.make_unique();
float* old_data(origin_);
int old_stride;
-
+
data_=new float [w_*h_];
origin_=data_;
stride_=w_;
-
+
for(int i=0;i<h;i++)
memcpy(data_+i*stride_,old_data+i*old_stride,sizeof(float)*w_);
}
SurfaceNew::create(int w, int h, ColorSystem sys=COLORSYS_RGB)
{
Handle ret(new SurfaceNew);
-
+
ret.set_wh(w,h);
ret.set_color_system(sys);
-
+
return ret;
}
SurfaceNew::create(HandleConst orig)
{
Lock lock(orig);
-
+
Handle ret(new SurfaceNew);
ret.w_=orig.w_;
ret.color_system_=orig.color_system_;
ret.premult_flag_=orig.premult_flag_;
ret.channel_map_=orig.channel_map_;
-
+
return ret;
}
SurfaceNew::crop(HandleConst, int x, int y, int w, int h)
{
Lock lock(orig);
-
+
Handle ret(new SurfaceNew);
ret.w_=orig.w_;
std::map<Channel,ChannelData>::iterator iter;
for(iter=ret.channel_map_.begin();iter!=ret.channel_map_.end();++iter)
iter->crop(x,y,w,h);
-
+
return ret;
}
{
return w_;
}
-
+
int
SurfaceNew::get_h()const
{
return h_;
}
-
+
void
SurfaceNew::set_wh(int w, int h)
{
{
// This operation is rather expensive, as it should be.
// I want to discurage people from using it all over the place.
-
+
Color ret(
lock_channel_const(CHAN_R).get_value(x,y),
lock_channel_const(CHAN_G).get_value(x,y),
lock_channel_const(CHAN_B).get_value(x,y),
lock_channel_const(CHAN_A).get_value(x,y)
);
-
+
if(get_premult())
{
ret=ret.demult_alpha();
}
-
+
return ret;
}
-
+
void
SurfaceNew::lock()
{
mutex_.lock();
}
-
+
void
SurfaceNew::unlock()
{
mutex_.unlock();
}
-
+
bool
SurfaceNew::trylock()
{
return mutex_.trylock();
}
-
+
SurfaceNew::ChannelLock
SurfaceNew::lock_channel(SurfaceNew::Channel chan)
{
channel_map_[chan].make_unique();
ChannelLockConst channel_lock;
-
+
channel_lock.surface_=this;
channel_lock.channel_=chan;
channel_map_[chan].rw_lock.writer_lock();
-
+
return channel_lock;
}
channel_map_[chan].set_wh(get_w(),get_h());
ChannelLockConst channel_lock;
-
+
channel_lock.surface_=this;
channel_lock.channel_=chan;
channel_map_[chan].rw_lock.reader_lock();
-
+
return channel_lock;
}
{
if(x==premult_flag_)
return;
-
+
premult_flag_=x;
-
+
for(int i=0;i<3;i++)
{
Channel chan;
case 1: chan=CHAN_U;
case 2: chan=CHAN_V;
}
-
+
// If this channel isn't defined, then
// skip it and move on to the next one
if(!is_channel_defined(chan))
continue;
-
+
ChannelLock color_channel(lock_channel(chan));
ChannelLockConst alpha_channel(lock_channel_alpha_const(chan));
const int w(get_w());
const int h(get_h());
-
+
float* color_ptr(color_channel.get_data_ptr());
const float* alpha_ptr(alpha_channel.get_data_ptr());
-
+
const int color_pitch(color_channel.get_data_ptr_stride()-w);
const int alpha_pitch(alpha_channel.get_data_ptr_stride()-w);
-
+
if(premult_flag_)
{
for(int y=0;y<h;y++,color_ptr+=color_pitch,alpha_ptr+=alpha_pitch)
)
{
int w(src->get_w()), h(src->get_h);
-
+
// Clip
{
int x(0), y(0);
-
+
if(x_dest+w>dest.get_w())
w=dest.get_w()-x_dest;
if(y_dest+h>dest.get_h())
}
src=crop(src,x,y,w,h);
}
-
+
dest=crop(dest,x_dest,y_dest,w,h);
if(bm==Color::BLEND_STRAIGHT)
chan_add(dest,src);
chan_mlt(dest,(1.0-amount)/amount);
}
-
+
if(bm==Color::BLEND_COMPOSITE)
{
-
+
}
}
{
if(data_ptr_checked_out_)
release_data_ptr();
-
+
if(surface_ && ref_count_.is_unique())
return surface->channel_map_[channel_].rw_lock.reader_unlock();
surface=0;
{
return surface_->get_w();
}
-
+
int
SurfaceChannelLockConst::get_h()const
{
return surface_->get_h();
}
-
+
float
SurfaceChannelLockConst::get_value(int x, int y)
{
SurfaceChannelLockConst::get_data_ptr()const
{
data_ptr_checked_out_=true;
-
+
// WOW! CRAZY SLOW!
return surface_->channel_map_[channel_].get_data();
}
const int w(dest.get_w());
const int h(dest.get_h());
const int pitch(dest.get_data_pitch()-w);
-
+
int(y=0;y<h;y++,ptr+=pitch)
int(x=0;x<w;x++,ptr++)
*ptr*=x;
const int h(dest.get_h());
const int d_pitch(dest.get_data_stride()-w);
const int s_pitch(x.get_data_stride()-w);
-
+
int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
int(x=0;x<w;x++,d_ptr++,s_ptr++)
*d_ptr *= *s_ptr;
const int w(dest.get_w());
const int h(dest.get_h());
const int pitch(dest.get_data_pitch()-w);
-
+
int(y=0;y<h;y++,ptr+=pitch)
int(x=0;x<w;x++,ptr++)
*ptr/=x;
const int h(dest.get_h());
const int d_pitch(dest.get_data_stride()-w);
const int s_pitch(x.get_data_stride()-w);
-
+
int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
int(x=0;x<w;x++,d_ptr++,s_ptr++)
*d_ptr /= *s_ptr;
const int w(dest.get_w());
const int h(dest.get_h());
const int pitch(dest.get_data_pitch()-w);
-
+
int(y=0;y<h;y++,ptr+=pitch)
int(x=0;x<w;x++,ptr++)
*ptr+=x;
const int h(dest.get_h());
const int d_pitch(dest.get_data_stride()-w);
const int s_pitch(x.get_data_stride()-w);
-
+
int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
int(x=0;x<w;x++,d_ptr++,s_ptr++)
*d_ptr += *s_ptr;
const int w(dest.get_w());
const int h(dest.get_h());
const int pitch(dest.get_data_pitch()-w);
-
+
int(y=0;y<h;y++,ptr+=pitch)
int(x=0;x<w;x++,ptr++)
*ptr-=x;
const int h(dest.get_h());
const int d_pitch(dest.get_data_stride()-w);
const int s_pitch(x.get_data_stride()-w);
-
+
int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
int(x=0;x<w;x++,d_ptr++,s_ptr++)
*d_ptr -= *s_ptr;
{
COLORSYS_RGB,
COLORSYS_YUV,
-
+
COLORSYS_END
}; // END of enum SurfaceColorSystem
-- ** -- T Y P E S -----------------------------------------------------------
*/
-public:
+public:
//! \writeme
typedef etl::handle<SurfaceNew> Handle;
//! \writeme
typedef etl::handle<const SurfaceNew> HandleConst;
-
+
//! \writeme
typedef etl::loose_handle<SurfaceNew> LooseHandle;
//! \writeme
typedef SurfaceColorSystem;
-
+
//! \writeme
class Lock
{
public:
Lock(const Handle& x):x(x) { x->lock(); }
void unlock() { if(x){ x->unlock(); x=0; } }
- ~Lock() { unlock(); }
+ ~Lock() { unlock(); }
}; // END of class Lock
friend class Lock;
-
+
private:
//! \writeme
class ChannelData;
-
+
/*
-- ** -- D A T A -------------------------------------------------------------
*/
private:
-
+
//! \writeme
RecMutex mutex_;
-
+
//! \writeme
int w_,h_;
//! \writeme
ColorSystem color_system_;
-
+
//! \writeme
bool premult_flag_;
//! \writeme
std::map<Channel,ChannelData> channel_map_;
-
+
/*
-- ** -- S I G N A L S -------------------------------------------------------
*/
*/
protected:
-
+
//! \writeme
SurfaceNew();
//! \writeme
int get_w()const;
-
+
//! \writeme
int get_h()const;
-
+
//! \writeme
void set_wh(int w, int h);
//! Should only be used in certain circumstances
Color get_color(int x, int y)const;
-
+
//! \writeme
void lock();
-
+
//! \writeme
void unlock();
-
+
//! \writeme
bool trylock();
-
+
//! \writeme
ChannelLock lock_channel(Channel chan);
//! \writeme
bool is_channel_defined(Channel chan)const;
-
+
//! \writeme
bool get_premult()const;
//! \writeme
void set_premult();
-
+
/*
-- ** -- S T A T I C F U N C T I O N S -------------------------------------
*/
//! Creates a cropped copy of a surface
static Handle crop(HandleConst, int x, int y, int w, int h);
-
+
static void blit(
Handle dest,
int x_dest,
float amount=1.0,
Color::BlendMethod bm=Color::BLEND_COMPOSITE
);
-
+
static void blit(
Handle dest,
int x_dest,
float amount=1.0,
Color::BlendMethod bm=Color::BLEND_COMPOSITE
);
-
-
+
+
static void chan_mlt(ChannelLock& dest, float x);
static void chan_mlt(ChannelLock& dest, const ChannelLockConst& x);
-- ** -- T Y P E S -----------------------------------------------------------
*/
-public:
+public:
/*
-- ** -- D A T A -------------------------------------------------------------
*/
protected:
-
+
//! \writeme
SurfaceNew::Handle surface_;
-
+
//! \writeme
etl::reference_counter ref_count_;
//! \writeme
bool data_ptr_checked_out_;
-
+
/*
-- ** -- C O N S T R U C T O R S ---------------------------------------------
*/
public:
SurfaceChannelLockConst();
-
+
//! \writeme
~SurfaceChannelLockConst();
*/
public:
-
+
//! \writeme
SurfaceChannel get_channel()const;
-
+
//! \writeme
int get_w()const;
-
+
//! \writeme
int get_h()const;
-
+
//! \writeme
float get_value(int x, int y);
-
+
//! \writeme
const float* get_data_ptr()const;
-
+
//! \writeme
int get_data_ptr_stride()const;
-
+
//! Releases the pointer obtained with get_data_ptr()
void release_data_ptr()const;
-
+
//! \writeme
operator bool()const;
}; // END of class SurfaceChannelLockConst
friend class SurfaceNew;
using SurfaceChannelLock::get_data_ptr;
-
+
/*
-- ** -- T Y P E S -----------------------------------------------------------
*/
-public:
+public:
/*
-- ** -- D A T A -------------------------------------------------------------
*/
private:
-
+
/*
-- ** -- C O N S T R U C T O R S ---------------------------------------------
*/
//! \writeme
void clear();
-
+
//! \writeme
void fill(float value);
-
+
//! \writeme
void set_value(int x, int y, float v);
{
book_=new synfig::Target::Book();
ext_book_=new synfig::Target::ExtBook();
-
+
default_gamma_=new synfig::Gamma(1.0/2.2);
//default_gamma_->set_black_level(0.05); // Default to 5% black level.
-
+
book()["null"]=std::pair<synfig::Target::Factory,String>(Target_Null::create,"null");
ext_book()["null"]="null";
book()["null-tile"]=std::pair<synfig::Target::Factory,String>(Target_Null_Tile::create,"null-tile");
{
if(!book().count(name))
return handle<Target>();
-
+
return Target::Handle(book()[name].first(filename.c_str()));
}
//! Map of target names indexed by associated file extension
static ExtBook* ext_book_;
-
+
static Book& book();
static ExtBook& ext_book();
static bool subsys_init();
static bool subsys_stop();
-
+
//! Adjusted Render description set by set_rend_desc()
RendDesc desc;
Gamma gamma_;
bool remove_alpha;
-
+
bool avoid_time_sync_;
-
+
protected:
Target();
virtual ~Target() { }
int get_quality()const { return quality_; }
-
+
void set_quality(int q) { quality_=q; }
-
+
void set_avoid_time_sync(bool x=true) { avoid_time_sync_=x; }
bool get_avoid_time_sync()const { return avoid_time_sync_; }
-
+
bool get_remove_alpha()const { return remove_alpha; }
void set_remove_alpha(bool x=true) { remove_alpha=x; }
-
+
Gamma &gamma() { return gamma_; }
const Gamma &gamma()const { return gamma_; }
RendDesc &rend_desc() { return desc; }
const RendDesc &rend_desc()const { return desc; }
-
+
//! Renders the canvas to the target
virtual bool render(ProgressCallback *cb=NULL)=0;
virtual void end_frame();
virtual Color * start_scanline(int scanline);
virtual bool end_scanline();
-
+
virtual void set_canvas(etl::handle<Canvas> c);
virtual bool set_rend_desc(RendDesc *d);
virtual bool init();
class Target_Null : public Target_Scanline
{
Color *buffer;
-
+
Target_Null():buffer(0) { }
-
+
public:
- ~Target_Null() { delete buffer; }
+ ~Target_Null() { delete buffer; }
virtual bool start_frame(ProgressCallback *cb=NULL)
{ delete buffer; buffer=new Color[desc.get_w()*sizeof(Color)]; return true; }
virtual Color * start_scanline(int scanline) { return buffer; }
virtual bool end_scanline() { return true; }
-
+
static Target* create(const char *filename=0) { return new Target_Null(); }
}; // END of class Target_Null
class Target_Null_Tile : public Target_Tile
{
Target_Null_Tile() { }
-
+
public:
- ~Target_Null_Tile() { }
+ ~Target_Null_Tile() { }
virtual bool add_tile(const synfig::Surface &surface, int x, int y) { return true; }
virtual bool start_frame(ProgressCallback *cb=NULL)
{ return true; }
virtual void end_frame() { return; }
-
+
static Target* create(const char *filename=0) { return new Target_Null_Tile(); }
}; // END of class Target_Null_Tile
frame_end=desc.get_frame_end();
time_start=desc.get_time_start();
time_end=desc.get_time_end();
-
+
// Calculate the number of frames
total_frames=frame_end-frame_start;
if(total_frames<=0)total_frames=1;
-
+
//RendDesc rend_desc=desc;
//rend_desc.set_gamma(1);
if(cb) cb->error(_("Target initialisation failure"));
return false;
}
-
+
// If the description's end frame is equal to
// the start frame, then it is assumed that we
// are rendering only one frame. Correct it.
frame_end=desc.get_frame_end();
time_start=desc.get_time_start();
time_end=desc.get_time_end();
-
+
// Calculate the number of frames
total_frames=frame_end-frame_start;
-
-
+
+
//RendDesc rend_desc=desc;
-
+
try {
// Grab the time
int i=next_frame(t);
-
+
//synfig::info("1time_set_to %s",t.get_string().c_str());
-
+
if(i>1)
do{
-
+
//if(total_frames>1)
//for(i=0,t=time_start;i<total_frames;i++)
//{
// false, go ahead and bail. (it may be a user cancel)
if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
return false;
-
+
// Set the time that we wish to render
if(!get_avoid_time_sync() || canvas->get_time()!=t)
canvas->set_time(t);
-
+
Context context;
-
+
#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
Canvas::Handle op_canvas(Canvas::create());
optimize_layers(canvas->get_context(), op_canvas);
#else
context=canvas->get_context();
#endif
-
+
// If the quality is set to zero, then we
// use the parametric scanline-renderer.
if(quality==0)
{
#if USE_PIXELRENDERING_LIMIT
if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
- {
+ {
synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
-
- Surface surface;
+
+ Surface surface;
int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
int rows = desc.get_h()/rowheight;
int lastrowheight = desc.get_h() - rows*rowheight;
-
+
rows++;
-
- synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
-
+
+ synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
+
// loop through all the full rows
if(!start_frame())
{
throw(string("add_frame(): target panic on start_frame()"));
return false;
}
-
+
for(int i=0; i < rows; ++i)
{
RendDesc blockrd = desc;
-
+
//render the strip at the normal size unless it's the last one...
if(i == rows)
{
{
blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
}
-
+
if(!context.accelerated_render(&surface,quality,blockrd,0))
{
if(cb)cb->error(_("Accelerated Renderer Failure"));
int y;
int rowspan=sizeof(Color)*surface.get_w();
Surface::pen pen = surface.begin();
-
+
int yoff = i*rowheight;
-
+
for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
{
Color *colordata= start_scanline(y + yoff);
throw(string("add_frame(): call to start_scanline(y) returned NULL"));
return false;
}
-
+
if(get_remove_alpha())
{
for(int i = 0; i < surface.get_w(); i++)
}
else
memcpy(colordata,surface[y],rowspan);
-
+
if(!end_scanline())
{
throw(string("add_frame(): target panic on end_scanline()"));
}
}
}
- }
+ }
+
+ end_frame();
- end_frame();
-
}else //use normal rendering...
{
#endif
Surface surface;
-
+
if(!context.accelerated_render(&surface,quality,desc,0))
{
// For some reason, the accelerated renderer failed.
if(!get_avoid_time_sync() || canvas->get_time()!=t)
canvas->set_time(t);
Context context;
-
+
#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
Canvas::Handle op_canvas(Canvas::create());
optimize_layers(canvas->get_context(), op_canvas);
#else
context=canvas->get_context();
#endif
-
+
// If the quality is set to zero, then we
// use the parametric scanline-renderer.
if(quality==0)
if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
{
synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
-
- Surface surface;
- int totalheight = desc.get_h();
+
+ Surface surface;
+ int totalheight = desc.get_h();
int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
int rows = desc.get_h()/rowheight;
int lastrowheight = desc.get_h() - rows*rowheight;
-
+
rows++;
-
- synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
-
+
+ synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
+
// loop through all the full rows
if(!start_frame())
{
throw(string("add_frame(): target panic on start_frame()"));
return false;
}
-
+
for(int i=0; i < rows; ++i)
{
RendDesc blockrd = desc;
-
+
//render the strip at the normal size unless it's the last one...
if(i == rows)
{
{
blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
}
-
+
SuperCallback sc(cb, i*rowheight, (i+1)*rowheight, totalheight);
-
+
if(!context.accelerated_render(&surface,quality,blockrd,&sc))
{
if(cb)cb->error(_("Accelerated Renderer Failure"));
int y;
int rowspan=sizeof(Color)*surface.get_w();
Surface::pen pen = surface.begin();
-
+
int yoff = i*rowheight;
-
+
for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
{
Color *colordata= start_scanline(y + yoff);
throw(string("add_frame(): call to start_scanline(y) returned NULL"));
return false;
}
-
+
if(get_remove_alpha())
{
for(int i = 0; i < surface.get_w(); i++)
}
else
memcpy(colordata,surface[y],rowspan);
-
+
if(!end_scanline())
{
throw(string("add_frame(): target panic on end_scanline()"));
}
}
}
-
+
//I'm done with this part
sc.amount_complete(100,100);
- }
+ }
+
+ end_frame();
- end_frame();
-
}else
{
- #endif
+ #endif
Surface surface;
-
+
if(!context.accelerated_render(&surface,quality,desc,cb))
{
if(cb)cb->error(_("Accelerated Renderer Failure"));
#endif
}
}
-
+
}
catch(String str)
{
int y;
int rowspan=sizeof(Color)*surface->get_w();
Surface::const_pen pen=surface->begin();
-
+
if(!start_frame())
{
throw(string("add_frame(): target panic on start_frame()"));
return false;
}
-
+
for(y=0;y<surface->get_h();y++,pen.inc_y())
{
Color *colordata= start_scanline(y);
throw(string("add_frame(): call to start_scanline(y) returned NULL"));
return false;
}
-
+
if(get_remove_alpha())
{
for(int i=0;i<surface->get_w();i++)
}
else
memcpy(colordata,(*surface)[y],rowspan);
-
+
if(!end_scanline())
{
throw(string("add_frame(): target panic on end_scanline()"));
return false;
}
}
-
+
end_frame();
-
+
return true;
}
** \see start_scanline()
*/
virtual bool end_scanline()=0;
-
+
void set_threads(int x) { threads_=x; }
int get_threads()const { return threads_; }
frame_end=desc.get_frame_end();
time_start=desc.get_time_start();
time_end=desc.get_time_end();
-
+
// Calculate the number of frames
total_frames=frame_end-frame_start;
if(total_frames<=0)total_frames=1;
-
+
//RendDesc rend_desc=desc;
//rend_desc.set_gamma(1);
// Add the last tiles (which will be clipped)
if(rend_desc().get_w()%tile_w_!=0)tw++;
if(rend_desc().get_h()%tile_h_!=0)th++;
-
+
x=(curr_tile_%tw)*tile_h_;
y=(curr_tile_/tw)*tile_w_;
etl::clock::value_type find_tile_time(0);
etl::clock::value_type add_tile_time(0);
total_time.reset();
-
+
// If the quality is set to zero, then we
// use the parametric scanline-renderer.
if(get_quality()==0)
{
Surface surface;
-
+
RendDesc tile_desc;
int x,y,w,h;
int i;
if(get_remove_alpha())
for(int i=0;i<surface.get_w()*surface.get_h();i++)
surface[0][i]=Color::blend(surface[0][i],desc.get_bg_color(),1.0f);
-
+
// Add the tile to the target
if(!add_tile(surface,x,y))
{
else // If quality is set otherwise, then we use the accelerated renderer
{
Surface surface;
-
+
RendDesc tile_desc;
int x,y,w,h;
int i;
tile_desc=rend_desc;
tile_desc.set_subwindow(x,y,w,h);
-
+
etl::clock timer2;
timer2.reset();
-
+
if(!context.accelerated_render(&surface,get_quality(),tile_desc,&super))
{
// For some reason, the accelerated renderer failed.
}
if(cb && !cb->amount_complete(total_tiles,total_tiles))
return false;
-
+
#if SYNFIG_DISPLAY_EFFICIENCY==1
synfig::info(">>>>>> Render Time: %fsec, Find Tile Time: %fsec, Add Tile Time: %fsec, Total Time: %fsec",work_time,find_tile_time,add_tile_time,total_time());
synfig::info(">>>>>> FRAME EFICIENCY: %f%%",(100.0f*work_time/total_time()));
return false;
}
-
+
// If the description's end frame is equal to
// the start frame, then it is assumed that we
// are rendering only one frame. Correct it.
frame_end=desc.get_frame_end();
time_start=desc.get_time_start();
time_end=desc.get_time_end();
-
+
// Calculate the number of frames
total_frames=frame_end-frame_start;
-
-
-
+
+
+
try {
// Grab the time
i=next_frame(t);
-
+
//synfig::info("1time_set_to %s",t.get_string().c_str());
-
+
if(i>=1)
{
do
{
curr_tile_=0;
-
+
// If we have a callback, and it returns
// false, go ahead and bail. (maybe a use cancel)
if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
return false;
-
+
if(!start_frame(cb))
return false;
// Set the time that we wish to render
//if(!get_avoid_time_sync() || canvas->get_time()!=t)
canvas->set_time(t);
-
+
Context context;
-
+
#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
Canvas::Handle op_canvas(Canvas::create());
optimize_layers(canvas->get_context(), op_canvas);
#else
context=canvas->get_context();
#endif
-
+
/*
#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
Context context;
context=canvas->get_context();
#endif
*/
-
+
if(!render_frame_(context,0))
return false;
end_frame();
else
{
curr_tile_=0;
-
+
if(!start_frame(cb))
return false;
//synfig::info("2time_set_to %s",t.get_string().c_str());
Context context;
-
+
#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
Canvas::Handle op_canvas(Canvas::create());
optimize_layers(canvas->get_context(), op_canvas);
#else
context=canvas->get_context();
#endif
-
+
if(!render_frame_(context, cb))
return false;
end_frame();
}
-
+
}
catch(String str)
{
virtual bool render(ProgressCallback *cb=NULL);
//! Determines which tile needs to be rendered next.
- /*! Most cases will not have to redefine this function.
+ /*! Most cases will not have to redefine this function.
** The default should be adequate in nearly all situations.
** \returns The number of tiles left to go <i>plus one</i>.
** This means that whenever this function returns zero,
virtual int next_frame(Time& time);
- //! Adds the tile at \a x , \a y contained in \a surface
+ //! Adds the tile at \a x , \a y contained in \a surface
virtual bool add_tile(const synfig::Surface &surface, int x, int y)=0;
virtual int total_tiles()const
// Width of the image(in tiles)
const int tw(rend_desc().get_w()/tile_w_+(rend_desc().get_w()%tile_w_?1:0));
const int th(rend_desc().get_h()/tile_h_+(rend_desc().get_h()%tile_h_?1:0));
-
+
return tw*th;
}
//! Marks the end of a frame
/*! \see start_frame() */
virtual void end_frame()=0;
-
+
void set_threads(int x) { threads_=x; }
int get_threads()const { return threads_; }
void set_tile_h(int h) { tile_h_=h; }
int get_tile_h()const { return tile_h_; }
-
+
bool get_clipping()const { return clipping_; }
void set_clipping(bool x) { clipping_=x; }
-
+
private:
-
+
bool render_frame_(Context context,ProgressCallback *cb=0);
-
+
}; // END of class Target_Tile
}; // END of namespace synfig
unsigned int pos=0;
int read;
float amount;
-
+
// Now try to read it in the letter-abreviated format
while(pos<str.size() && sscanf(String(str,pos).c_str(),"%f%n",&amount,&read))
{
value_=frame/fps+(hour*3600+minute*60+second);
return;
}
-
+
if(sscanf(str.c_str(),"%d:%d:%d",&hour,&minute,&second)==3)
{
value_=hour*3600+minute*60+second;
Time::get_string(float fps, Time::Format format)const
{
Time time(*this);
-
+
if(time<=begin())
return "SOT"; // Start Of Time
if(time>=end())
return "EOT"; // End Of Time
-
+
if(fps<0)fps=0;
-
+
if(ceil(time.value_)-time.value_<epsilon_())
time.value_=ceil(time.value_);
-
+
int hour,minute;
-
+
hour=time/3600;time-=hour*3600;
minute=time/60;time-=minute*60;
-
+
if(format<=FORMAT_VIDEO)
{
int second;
else
return strprintf("%02d:%02d:%02d",hour,minute,second);
}
-
+
String ret;
if(format<=FORMAT_FULL || hour)
ret+=strprintf(format<=FORMAT_NOSPACES?"%dh":"%dh ",hour);
-
+
if(format<=FORMAT_FULL || hour || minute)
ret+=strprintf(format<=FORMAT_NOSPACES?"%dm":"%dm ",minute);
-
+
if(fps)
{
int second;
frame=time*fps;
if(format<=FORMAT_FULL || second)
ret+=strprintf(format<=FORMAT_NOSPACES?"%ds":"%ds ",(int)second);
-
+
if(abs(frame-floor(frame)>=epsilon_()))
ret+=strprintf("%0.3ff",frame);
else
else
ret+=strprintf("%0.0fs",second);
}
-
+
return ret;
}
FORMAT_NOSPACES=(1<<0), //!< Remove any whitespace
FORMAT_FULL=(1<<1), //!< Do not remove units that have "zero" value
FORMAT_VIDEO=(1<<2), //!< Use the HH:MM:SS.ff format
-
+
FORMAT_END=(1<<4) //!< \internal Not used
}; // END of enum Format
//! Marks the exclusive negative boundary of time
static const Time begin() { return static_cast<synfig::Time>(-32767.0f*512.0f); }
-
+
//! Marks the exclusive positive boundary of time
static const Time end() { return static_cast<synfig::Time>(32767.0f*512.0f); }
//! Marks zero time
static const Time zero() { return static_cast<synfig::Time>(0); }
-
+
//! The amount of allowable error in calculations
static const Time epsilon() { return static_cast<synfig::Time>(epsilon_()); }
-
+
//! Returns a string describing the current time value
/*! \see Format */
String get_string(float fps=0, Time::Format format=FORMAT_NORMAL)const;
-
+
//! \writeme
bool is_valid()const;
-
+
//! Rounds time to the nearest frame for the given frame rate, \a fps
Time round(float fps)const;
bool is_equal(const Time& rhs)const { return (value_>rhs.value_)?value_-rhs.value_<=epsilon_():rhs.value_-value_<=epsilon_(); }
bool is_less_than(const Time& rhs)const { return rhs.value_-value_ > epsilon_(); }
bool is_more_than(const Time& rhs)const { return value_-rhs.value_ > epsilon_(); }
-
+
operator double()const { return value_; }
template<typename U> bool operator<(const U& rhs)const { return value_<rhs; }
bool operator==(const Time& rhs)const { return is_equal(rhs); }
bool operator!=(const Time& rhs)const { return !is_equal(rhs); }
#endif
-
+
template<typename U> const Time& operator+=(const U &rhs) { value_+=static_cast<value_type>(rhs); return *this; }
template<typename U> const Time& operator-=(const U &rhs) { value_-=static_cast<value_type>(rhs); return *this; }
template<typename U> const Time& operator*=(const U &rhs) { value_*=static_cast<value_type>(rhs); return *this; }
template<typename U> Time operator-(const U &rhs)const { return value_-static_cast<value_type>(rhs); }
template<typename U> Time operator*(const U &rhs)const { return value_*static_cast<value_type>(rhs); }
template<typename U> Time operator/(const U &rhs)const { return value_/static_cast<value_type>(rhs); }
-
+
Time operator-()const { return -value_; }
}; // END of class Time
{ return (static_cast<int>(lhs) & static_cast<int>(rhs))==static_cast<int>(rhs); }
}; // END of namespace synfig
-
+
/* === E N D =============================================================== */
#endif
//! \writeme
int
synfig::waypoint_collect(set<Waypoint, std::less<UniqueID> >& waypoint_set,const Time& time, const etl::handle<Node>& node)
-{
+{
const TimePointSet& timepoint_set(node->get_times());
// Check to see if there is anything in here at the given time
{
try{
Waypoint waypoint=*value_node_animated->find(time);
-
+
// If it is already in the waypoint set, then
// don't bother adding it again
if(waypoint_set.find(waypoint)!=waypoint_set.end())
//! \writeme
int activepoint_collect(std::set<Activepoint, std::less<UniqueID> >& activepoint_set,const Time& time, const etl::handle<Node>& node);
-
+
}; // END of namespace synfig
/* === E N D =============================================================== */
TransformStack::get_guid()const
{
GUID ret(0);
-
+
for(const_iterator iter(begin());iter!=end();++iter)
ret%=(*iter)->get_guid();
return ret;
TransformStack::perform(const synfig::Vector& x)const
{
synfig::Vector ret(x);
-
+
for(const_reverse_iterator iter(rbegin());iter!=rend();++iter)
ret=(*iter)->perform(ret);
-
+
return ret;
}
TransformStack::unperform(const synfig::Vector& x)const
{
synfig::Vector ret(x);
-
+
for(const_iterator iter(begin());iter!=end();++iter)
ret=(*iter)->unperform(ret);
-
+
return ret;
}
Point min(x.get_min());
Point max(x.get_max());
-
+
Rect ret(unperform(min),unperform(max));
std::swap(min[1],max[1]);
class Transform : public etl::shared_object
{
GUID guid_;
-
+
public:
typedef etl::handle<Transform> Handle;
synfig::Vector perform(const synfig::Vector& x)const;
synfig::Vector unperform(const synfig::Vector& x)const;
-
+
synfig::Rect perform(const synfig::Rect& x)const;
synfig::Rect unperform(const synfig::Rect& x)const;
-
+
void push(const Transform::Handle& x) { if(x)push_back(x); }
void pop() { pop_back(); }
}; // END of class TransformStack
/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {
-
+
class UniqueIDLessThan;
-
+
/*! \class UniqueID
** \brief \todo
*/
class UniqueID
{
friend class UniqueIDLessThan;
-
+
int id_;
-
+
explicit UniqueID(int id_):id_(id_) { }
-
+
static int next_id();
-
+
public:
-
+
//! Returns the internal unique identifier for this object.
/*! The return value from this isn't really useful for
** much other than debug output. Nonetheless, that is
** one step above useless, so here it is. */
const int &get_uid()const { return id_; }
-
+
UniqueID():id_(next_id()) { }
-
+
void make_unique() { id_=next_id(); }
-
+
static const UniqueID nil() { return UniqueID(0); }
-
+
operator bool()const { return static_cast<bool>(id_); }
void mimic(const UniqueID& x) { id_=x.id_; }
-
+
bool operator==(const UniqueID &rhs)const { return id_==rhs.id_; }
bool operator!=(const UniqueID &rhs)const { return id_!=rhs.id_; }
bool operator<(const UniqueID &rhs)const { return id_<rhs.id_; }
break;
}
}
-
+
ref_count.detach();
data=0;
type=TYPE_NIL;
return false;
if(data==rhs.data)
return true;
-
+
switch(get_type())
{
case TYPE_TIME:
class Gradient;
class BLinePoint;
class Color;
-
+
/*! \class ValueBase
** \todo writeme
*/
enum Type
{
TYPE_NIL=0, //!< Represents an empty value
-
+
TYPE_BOOL,
TYPE_INTEGER,
TYPE_ANGLE, //!< Angle
// All types after this point are larger than 32 bits
-
+
TYPE_TIME, //!< Time
TYPE_REAL, //!< Real
// All types after this point are larger than 64 bits
-
+
TYPE_VECTOR, //!< Vector
TYPE_COLOR, //!< Color
TYPE_SEGMENT, //!< Segment
TYPE_BLINEPOINT, //!< BLinePoint
// All types after this point require construction/destruction
-
+
TYPE_LIST, //!< List
TYPE_CANVAS, //!< Canvas
TYPE_STRING, //!< String
TYPE_END //!< Not a valid type, used for sanity checks
};
-
+
private:
typedef std::vector<ValueBase> list_type;
*/
protected:
-
+
Type type;
void *data;
etl::reference_counter ref_count;
- bool loop_;
+ bool loop_;
/*
-- ** -- C O N S T R U C T O R S -----------------------------------
*/
-
+
public:
//! \writeme
//! \writeme
~ValueBase();
-
+
/*
-- ** -- O P E R A T O R S ---------------------------------------------------
*/
{ set(x); return *this; }
//! \writeme
- ValueBase& operator=(const ValueBase& x);
+ ValueBase& operator=(const ValueBase& x);
//! \writeme
bool operator==(const ValueBase& rhs)const;
bool get_loop()const { return loop_; }
//! \writeme
- void set_loop(bool x) { loop_=x; }
-
+ void set_loop(bool x) { loop_=x; }
+
//! \writeme
bool empty()const;
//! \writeme
Type get_contained_type()const;
-
+
//! Returns true if the contained value is defined and valid.
bool is_valid()const;
//! Returns the type of the contained value
const Type & get_type()const { return type; }
-
+
//! Checks the type of the parameter against itself. Returns true if they are of the same type.
template <class T> bool
same_as(const T &x)const
{
const Type testtype(get_type(x));
-
+
if(testtype==type)return true;
if( (type==TYPE_REAL || type==TYPE_TIME) &&
(testtype==TYPE_REAL || testtype==TYPE_TIME) )
return true;
return false;
}
-
-
- // === GET MEMBERS ========================================================
+
+
+ // === GET MEMBERS ========================================================
template <typename T>
const T &get(const T& x)const
{
const char* get(const char*)const;
const list_type& get_list()const { return get(list_type()); }
// ========================================================================
-
-
-
- // === PUT MEMBERS ========================================================
+
+
+
+ // === PUT MEMBERS ========================================================
template <typename T>
void put(T* x)const
{
void put(char** x)const;
// ========================================================================
-
-
- // === SET MEMBERS ========================================================
+
+
+ // === SET MEMBERS ========================================================
template <typename T> void set(const T& x) { _set(x); }
void set(const float &x) { _set(Real(x)); }
void set(const list_type &x);
- void set(const char* x);
+ void set(const char* x);
void set(Canvas*x);
void set(etl::loose_handle<Canvas> x);
void set(etl::handle<Canvas> x);
template <class T> void set(const std::vector<T> &x)
{ _set(list_type(x.begin(),x.end())); }
template <class T> void set(const std::list<T> &x)
- { _set(list_type(x.begin(),x.end())); }
+ { _set(list_type(x.begin(),x.end())); }
// ========================================================================
-
+
/*
-- ** -- S T A T I C F U N C T I O N S -------------------------------------
*/
static Type ident_type(const String &str);
- // === GET TYPE MEMBERS ===================================================
+ // === GET TYPE MEMBERS ===================================================
static const Type get_type(bool) { return TYPE_BOOL; }
static const Type get_type(int) { return TYPE_INTEGER; }
static const Type get_type(const Time&) { return TYPE_TIME; }
static const Type get_type(const etl::handle<Canvas>&)
{ return TYPE_CANVAS; }
static const Type get_type(const etl::loose_handle<Canvas>&)
- { return TYPE_CANVAS; }
+ { return TYPE_CANVAS; }
static const Type get_type(const list_type&) { return TYPE_LIST; }
template <class T> static const Type get_type(const std::vector<T> &x)
{ return TYPE_LIST; }
{ return TYPE_LIST; }
// ========================================================================
-
+
/*
-- ** -- C A S T O P E R A T O R S -----------------------------------------
*/
//operator const Color&()const { return get(Color()); }
//operator const Real&()const { return get(Real()); }
//operator const Time&()const { return get(Time()); }
-
+
operator const Vector&()const { return get(Vector()); }
operator const BLinePoint&()const { return get(BLinePoint()); }
//operator const int&()const { return get(int()); }
static const Type get_type(const half&) { return TYPE_REAL; }
operator half()const { return get(Real()); }
#endif
-
+
#ifndef SYNFIG_NO_ANGLE
operator const Angle&()const { return get(Angle()); }
static const Type get_type(const Angle&) { return TYPE_ANGLE; }
return ret;
}
-
+
private:
-
+
template <typename T> void
_set(const T& x)
{
const Type newtype(get_type(x));
-
+
assert(newtype!=TYPE_NIL);
-
+
if(newtype==type)
{
if(ref_count.unique())
type=newtype;
ref_count.reset();
data=new T(x);
- }
+ }
}; // END of class ValueBase
Value(const T &x):ValueBase(x)
{
}
-
+
Value(const ValueBase &x):ValueBase(x)
{
if(!x.same_as(T()))
throw Exception::BadType("Value<T>(ValueBase): Type Mismatch");
}
-
+
Value()
{
}
-
+
T get()const { return ValueBase::get(T()); }
void put(T* x)const { ValueBase::put(x); }
-
+
void set(const T& x) { ValueBase::operator=(x); }
Value<T>& operator=(const T& x) { set(x); return *this; }
throw Exception::BadType("Value<T>(ValueBase): Type Mismatch");
return ValueBase::operator=(x);
}
-
+
}; // END of class Value
/*
Value()
{
}
-
+
T get()const { return ValueBase::get(T()); }
void put(T* x)const { ValueBase::put(x); }
-
+
void set(const T& x) { ValueBase::operator=(x); }
Value<T>& operator=(const T& x) { set(x); return *this; }
throw Exception::BadType("Value<T>(ValueBase): Type Mismatch");
return ValueBase::operator=(x);
}
-
+
}; // END of class Value
*/
ADD_VALUENODE2(ValueNode_DynamicList,"dynamic_list");
ADD_VALUENODE(ValueNode_GradientRotate,"gradient_rotate");
ADD_VALUENODE(ValueNode_Sine,"sine");
-
+
#undef ADD_VALUENODE
return true;
}
if(global_value_node_map.size()!=value_node_count)
synfig::error("value node count mismatch! map.size()!=value_node_count (%d!=%d)",global_value_node_map.size(),value_node_count);
-
- GlobalValueNodeMap::iterator iter;
+
+ GlobalValueNodeMap::iterator iter;
for(iter=global_value_node_map.begin();iter!=global_value_node_map.end();++iter)
{
if(!iter->second->is_exported())
LinkableValueNode::set_link(int i,ValueNode::Handle x)
{
ValueNode::Handle previous(get_link(i));
-
+
if(set_link_vfunc(i,x))
{
if(previous)
remove_child(previous.get());
add_child(x.get());
-
+
if(!x->is_exported() && get_parent_canvas())
{
x->set_parent_canvas(get_parent_canvas());
ValueNode::~ValueNode()
{
value_node_count--;
-
+
begin_delete();
//DEBUGPOINT();
get_parent_canvas()->signal_value_node_changed()(this);
else if(get_root_canvas() && get_parent_canvas())
get_root_canvas()->signal_value_node_changed()(this);
-
+
Node::on_changed();
}
{
if(x.get()==this)
return 0;
-
+
while(parent_set.size())
{
(*parent_set.begin())->add_child(x.get());
{
if(id.empty())
throw Exception::IDNotFound("Empty ID");
-
+
ValueNode::Handle value_node;
-
+
try
{
value_node=find(id);
return false;
}
catch(Exception::IDNotFound)
- {
+ {
push_back(value_node);
return true;
}
-
+
return false;
}
int i;
LinkableValueNode *ret=create_new();
ret->set_guid(get_guid()^deriv_guid);
-
+
for(i=0;i<link_count();i++)
{
ValueNode::Handle link=get_link_vfunc(i);
{
assert(is_exported());
assert(canvas_);
-
+
if(x.get()==canvas_.get())
return get_id();
-
+
return canvas_->_get_relative_id(x)+':'+get_id();
}
void LinkableValueNode::get_times_vfunc(Node::time_set &set) const
{
ValueNode::LooseHandle h;
-
+
int size = link_count();
-
+
//just add it to the set...
for(int i=0; i < size; ++i)
{
class Canvas;
class LinkableValueNode;
class Layer;
-
+
/*! \class ValueNode
** \todo writeme
*/
{
friend class Layer;
friend class LinkableValueNode;
-
+
/*
-- ** -- T Y P E S -----------------------------------------------------------
*/
String name;
etl::loose_handle<Canvas> canvas_;
etl::loose_handle<Canvas> root_canvas_;
-
+
/*
-- ** -- S I G N A L S -------------------------------------------------------
*/
private:
//! ValueBase Changed
- sigc::signal<void> signal_value_changed_;
+ sigc::signal<void> signal_value_changed_;
//! Children Reordered
- sigc::signal<void,int*> signal_children_reordered_;
+ sigc::signal<void,int*> signal_children_reordered_;
//! Child Changed
- sigc::signal<void,int> signal_child_changed_;
+ sigc::signal<void,int> signal_child_changed_;
//! Child Removed
- sigc::signal<void,int> signal_child_removed_;
+ sigc::signal<void,int> signal_child_removed_;
//! Child Inserted
- sigc::signal<void,int> signal_child_inserted_;
+ sigc::signal<void,int> signal_child_inserted_;
//! ID Changed
- sigc::signal<void> signal_id_changed_;
+ sigc::signal<void> signal_id_changed_;
/*
-- ** -- S I G N A L I N T E R F A C E -------------------------------------
*/
protected:
-
+
ValueNode(ValueBase::Type type=ValueBase::TYPE_NIL);
public:
//! \writeme
bool is_exported()const { return !get_id().empty(); }
-
+
//! Returns the type of the ValueNode
ValueBase::Type get_type()const { return type; }
//! Returns a handle to the parent canvas, if it has one.
etl::loose_handle<Canvas> get_root_canvas()const { return root_canvas_; }
-
+
//! \writeme
void set_parent_canvas(etl::loose_handle<Canvas> x);
//! \writeme
void set_root_canvas(etl::loose_handle<Canvas> x);
-
+
//! \writeme
String get_relative_id(etl::loose_handle<const Canvas> x)const;
-
+
int replace(etl::handle<ValueNode> x);
-
+
protected:
//! Sets the type of the ValueNode
void set_type(ValueBase::Type t) { type=t; }
virtual void on_changed();
-
+
public:
DCAST_HACK_BASECLASS();
DCAST_HACK_ID(0);
PlaceholderValueNode(ValueBase::Type type=ValueBase::TYPE_NIL);
public:
-
+
virtual ValueBase operator()(Time t)const;
virtual String get_name()const;
{
String local_name;
Factory factory;
- CheckType check_type;
+ CheckType check_type;
};
-
+
typedef std::map<String,BookEntry> Book;
static Book& book();
void unlink_all();
public:
-
+
virtual int link_count()const=0;
virtual String link_local_name(int i)const=0;
virtual String link_name(int i)const=0;
virtual int get_link_index_from_name(const String &name)const=0;
-
+
virtual ValueNode* clone(const GUID& deriv_guid=GUID())const;
bool set_link(int i,ValueNode::Handle x);
- bool set_link(const String &name,ValueNode::Handle x) { return set_link(get_link_index_from_name(name),x); }
-
+ bool set_link(const String &name,ValueNode::Handle x) { return set_link(get_link_index_from_name(name),x); }
+
ValueNode::LooseHandle get_link(int i)const;
ValueNode::LooseHandle get_link(const String &name)const { return get_link(get_link_index_from_name(name)); }
// Wrapper for new operator, used by clone()
virtual LinkableValueNode* create_new()const=0;
-
+
virtual void get_times_vfunc(Node::time_set &set) const;
}; // END of class LinkableValueNode
//! Removes any value_nodes with reference counts of 1.
void audit();
-
+
//! Placeholder Count
int placeholder_count()const { return placeholder_count_; }
};
binary_find(I begin, I end, const T& value)
{
I iter(begin+(end-begin)/2);
-
+
while(end-begin>1 && !(*iter==value))
{
((*iter<value)?begin:end) = iter;
-
+
iter = begin+(end-begin)/2;
}
return iter;
{
is_angle_type<value_type> is_angle;
subtractor<value_type> subtract_func;
-
+
mutable hermite<Time,Time> first;
mutable hermite<value_type,Time> second;
WaypointList::iterator start;
WaypointList::iterator end;
-
+
value_type resolve(const Time &t)const
{
bool start_static(start->is_static());
bool end_static(end->is_static());
-
+
if(!start_static || !end_static)
{
//if(!start_static)
- second.p1()=start->get_value(t).get(value_type());
+ second.p1()=start->get_value(t).get(value_type());
if(start->get_after()==INTERPOLATION_CONSTANT || end->get_before()==INTERPOLATION_CONSTANT)
return second.p1();
//if(!end_static)
// that we support is linear.
second.t1()=
second.t2()=subtract_func(second.p2(),second.p1());
-
+
second.sync();
}
> curve_list_type;
curve_list_type curve_list;
-
+
// Bounds of this curve
Time r,s;
-
+
public:
ValueNode* clone(const GUID& deriv_guid)const
{
// Make sure we are getting data of the correct type
//if(data.type!=type)
// return waypoint_list_type::iterator();
-
+
try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
Waypoint waypoint(value,t);
waypoint.set_parent_value_node(this);
-
+
waypoint_list_.push_back(waypoint);
WaypointList::iterator ret=waypoint_list_.end();
--ret;
-
+
if(is_angle())
{
ret->set_before(INTERPOLATION_LINEAR);
ret->set_after(INTERPOLATION_LINEAR);
}
-
+
changed();
-
+
return ret;
}
//if(data.type!=type)
// return waypoint_list_type::iterator();
try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
-
+
Waypoint waypoint(value_node,t);
waypoint.set_parent_value_node(this);
-
+
waypoint_list_.push_back(waypoint);
WaypointList::iterator ret=waypoint_list_.end();
--ret;
}
changed();
-
+
return ret;
}
-
+
virtual void on_changed()
{
ValueNode_Animated::on_changed();
-
+
if(waypoint_list_.size()<=1)
return;
std::sort(waypoint_list_.begin(),waypoint_list_.end());
r=waypoint_list_.front().get_time();
s=waypoint_list_.back().get_time();
-
+
curve_list.clear();
-
+
WaypointList::iterator prev,iter,next=waypoint_list_.begin();
int i=0;
-
+
for(iter=next++;iter!=waypoint_list_.end() && next!=waypoint_list_.end();prev=iter,iter=next++,i++)
{
typename curve_list_type::value_type curve;
curve.start=iter;
curve.end=next;
-
+
// Set up the positions
curve.first.set_rs(iter->get_time(), next->get_time());
curve.second.set_rs(iter->get_time(), next->get_time());
-
+
Waypoint::Interpolation iter_get_after(iter->get_after());
Waypoint::Interpolation next_get_after(next->get_after());
Waypoint::Interpolation iter_get_before(iter->get_before());
Waypoint::Interpolation next_get_before(next->get_before());
-
+
if(is_angle())
{
if(iter_get_after==INTERPOLATION_TCB)
if(next_get_before==INTERPOLATION_TCB)
next_get_before=INTERPOLATION_LINEAR;
}
-
+
if(iter->is_static() && next->is_static())
{
curve.second.p1()=iter->get_value().get(T());
const Real& t(iter->get_tension()); // Tension
const Real& c(iter->get_continuity()); // Continuity
const Real& b(iter->get_bias()); // Bias
-
+
// The folloing line works where the previous line fails.
value_type Pp; Pp=curve_list.back().second.p1(); // P_{i-1}
-
+
const value_type& Pc(curve.second.p1()); // P_i
const value_type& Pn(curve.second.p2()); // P_{i+1}
-
+
// TCB
value_type vect(static_cast<value_type>(subtract_func(Pc,Pp)*(((1.0-t)*(1.0+c)*(1.0+b))/2.0)+(Pn-Pc)*(((1.0-t)*(1.0-c)*(1.0-b))/2.0)));
-
+
// Tension Only
//value_type vect=(value_type)((Pn-Pp)*(1.0-t));
-
+
// Linear
//value_type vect=(value_type)(Pn-Pc);
// Debugging stuff
//synfig::info("%d:t1: %s",i,tangent_info(Pp,Pn,vect).c_str());
-
+
// Adjust for time
//vect=value_type(vect*(curve.second.get_dt()*2.0)/(curve.second.get_dt()+curve_list.back().second.get_dt()));
//vect=value_type(vect*(curve.second.get_dt())/(curve_list.back().second.get_dt()));
-
+
curve.second.t1()=vect;
}
}
curve_list.back().second.sync();
}
-
+
if(next_get_before==INTERPOLATION_TCB && after_next!=waypoint_list_.end() && !is_angle())
{
const Real &t(next->get_tension()); // Tension
const value_type &Pp(curve.second.p1()); // P_{i-1}
const value_type &Pc(curve.second.p2()); // P_i
value_type Pn; Pn=after_next->get_value().get(T()); // P_{i+1}
-
+
// TCB
value_type vect(static_cast<value_type>(subtract_func(Pc,Pp)*(((1.0-t)*(1.0-c)*(1.0+b))/2.0)+(Pn-Pc)*(((1.0-t)*(1.0+c)*(1.0-b))/2.0)));
// Tension Only
//value_type vect((value_type)((Pn-Pp)*(1.0-t)));
-
+
// Linear
//value_type vect=(value_type)(Pc-Pp);
// Adjust for time
const float timeadjust(0.5);
-
+
if(!curve_list.empty())
curve.second.t1()*=(curve.second.get_dt()*(timeadjust+1))/(curve.second.get_dt()*timeadjust+curve_list.back().second.get_dt());
if(after_next!=waypoint_list_.end())
if(iter_get_after==INTERPOLATION_HALT)
curve.second.t1()*=0;
-
+
if(next_get_before==INTERPOLATION_HALT)
- curve.second.t2()*=0;
+ curve.second.t2()*=0;
}
}
curve_list.push_back(curve);
}
}
-
+
virtual ValueBase operator()(Time t)const
{
if(waypoint_list_.empty())
return waypoint_list_.front().get_value(t);
if(t>=s)
return waypoint_list_.back().get_value(t);
-
+
typename curve_list_type::const_iterator iter;
// This next line will set iter to the
if(iter==curve_list.end())
return waypoint_list_.back().get_value(t);
return iter->resolve(t);
- }
-};
+ }
+};
template<typename T>
//if(data.type!=type)
// return waypoint_list_type::iterator();
try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
-
+
Waypoint waypoint(value,t);
waypoint.set_parent_value_node(this);
-
+
waypoint_list_.push_back(waypoint);
WaypointList::iterator ret=waypoint_list_.end();
--ret;
Waypoint waypoint(value_node,t);
waypoint.set_parent_value_node(this);
-
+
waypoint_list_.push_back(waypoint);
WaypointList::iterator ret=waypoint_list_.end();
--ret;
virtual void on_changed()
{
ValueNode_Animated::on_changed();
-
+
if(waypoint_list_.size()<=1)
return;
std::sort(waypoint_list_.begin(),waypoint_list_.end());
// return waypoint_list_type::iterator();
try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
-
+
Waypoint waypoint(value,t);
waypoint.set_parent_value_node(this);
-
+
waypoint_list_.push_back(waypoint);
WaypointList::iterator ret=waypoint_list_.end();
--ret;
Waypoint waypoint(value_node,t);
waypoint.set_parent_value_node(this);
-
+
waypoint_list_.push_back(waypoint);
WaypointList::iterator ret=waypoint_list_.end();
--ret;
virtual void on_changed()
{
ValueNode_Animated::on_changed();
-
+
if(waypoint_list_.size()<=1)
return;
std::sort(waypoint_list_.begin(),waypoint_list_.end());
if(iter->get_time()==t)
return iter->get_value(t);
-
+
if(next!=waypoint_list_.end())
return iter->get_value(t).get(bool()) || next->get_value(t).get(bool());
return iter->get_value(t);
{
Time curr_time(begin);
int ret(0);
-
+
// try to grab first waypoint
try
{
ret++;
}
catch(...) { }
-
+
try
{
WaypointList::iterator iter;
}
}
catch(...) { }
-
+
return ret;
}
throw Exception::BadTime(_("Waypoint Conflict"));
}
catch(Exception::NotFound) { }
-
+
selected.back()->set_time(old_2_new(selected.back()->get_time()));
selected.pop_back();
}
-
-
+
+
while(!selected.empty())
{
selected.back()->set_time(old_2_new(selected.back()->get_time()));
selected.pop_back();
}
-
+
changed();
}
#undef old_2_new
waypoint.make_unique();
}
catch(...)
- {
+ {
if(waypoint_list().empty())
{
waypoint.set_value((*this)(time));
WaypointList::const_iterator next;
bool has_prev(false), has_next(false);
-
+
try { prev=find_prev(time); has_prev=true; } catch(...) { }
try { next=find_next(time); has_next=true; } catch(...) { }
-
+
/*
WaypointList::const_iterator closest;
closest=prev;
else
closest=next;
-
+
for(iter=waypoint_list().begin();iter!=waypoint_list().end();++iter)
{
const Real dist(abs(iter->get_time()-time));
closest=iter;
}
*/
-
+
if(has_prev && !prev->is_static())
waypoint.set_value_node(prev->get_value_node());
if(has_next && !next->is_static())
waypoint.set_value_node(next->get_value_node());
else
waypoint.set_value((*this)(time));
-
+
/*if(has_prev)
waypoint.set_after(prev->get_before());
if(has_next)
waypoint.set_parent_value_node(const_cast<ValueNode_Animated*>(this));
// synfig::info("waypoint.get_after()=set to %d",waypoint.get_after());
// synfig::info("waypoint.get_before()=set to %d",waypoint.get_before());
-
+
return waypoint;
}
if(iter!=waypoint_list().end() && iter->get_time().is_more_than(x))
return iter;
}
-
+
throw Exception::NotFound(strprintf("ValueNode_Animated::find_next(): Can't find Waypoint after %s",x.get_string().c_str()));
}
if(iter!=waypoint_list().end() && iter->get_time()-Time::epsilon()>x)
return iter;
}
-
+
throw Exception::NotFound(strprintf("ValueNode_Animated::find_next(): Can't find Waypoint after %s",x.get_string().c_str()));
*/
}
if(iter!=waypoint_list().begin() && (--iter)->get_time().is_less_than(x))
return iter;
}
-
+
throw Exception::NotFound(strprintf("ValueNode_Animated::find_prev(): Can't find Waypoint after %s",x.get_string().c_str()));
}
return ValueNode_Animated::Handle(new _Hermite<Vector>);
case ValueBase::TYPE_COLOR:
return ValueNode_Animated::Handle(new _Hermite<Color>);
-
+
case ValueBase::TYPE_STRING:
return ValueNode_Animated::Handle(new _Constant<String>);
case ValueBase::TYPE_GRADIENT:
void ValueNode_Animated::get_times_vfunc(Node::time_set &set) const
{
//add all the way point times to the value node...
-
+
WaypointList::const_iterator i = waypoint_list().begin(),
end = waypoint_list().end();
struct timecmp
{
Time t;
-
+
timecmp(const Time &c) :t(c) {}
-
+
bool operator()(const Waypoint &rhs) const
{
return t.is_equal(rhs.get_time());
}
};
-
+
ValueNode_Animated::findresult
ValueNode_Animated::find_uid(const UniqueID &x)
{
findresult f;
f.second = false;
-
+
//search for it... and set the bool part of the return value to true if we found it!
f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
if(f.first != waypoint_list_.end())
f.second = true;
-
+
return f;
}
-
+
ValueNode_Animated::const_findresult
ValueNode_Animated::find_uid(const UniqueID &x)const
{
const_findresult f;
f.second = false;
-
+
//search for it... and set the bool part of the return value to true if we found it!
f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
if(f.first != waypoint_list_.end())
f.second = true;
-
+
return f;
}
-
- ValueNode_Animated::findresult
+
+ ValueNode_Animated::findresult
ValueNode_Animated::find_time(const Time &x)
{
findresult f;
f.second = false;
-
+
//search for it... and set the bool part of the return value to true if we found it!
f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
if(f.first != waypoint_list_.end())
f.second = true;
-
+
return f;
}
-
+
ValueNode_Animated::const_findresult
ValueNode_Animated::find_time(const Time &x)const
{
const_findresult f;
f.second = false;
-
+
//search for it... and set the bool part of the return value to true if we found it!
f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
if(f.first != waypoint_list_.end())
f.second = true;
-
+
return f;
}
typedef synfig::Waypoint Waypoint;
typedef synfig::WaypointList WaypointList;
-
+
typedef std::pair<WaypointList::iterator,bool> findresult;
typedef std::pair<WaypointList::const_iterator,bool> const_findresult;
/*! \note this does not add any waypoint to the ValueNode! */
Waypoint new_waypoint_at_time(const Time& t)const;
-
+
WaypointList::iterator add(const Waypoint &x);
void erase(const UniqueID &x);
-
- //either use find result (return bool and iterator) or
+
+ //either use find result (return bool and iterator) or
findresult find_uid(const UniqueID &x);
const_findresult find_uid(const UniqueID &x)const;
- findresult find_time(const Time &x);
+ findresult find_time(const Time &x);
const_findresult find_time(const Time &x)const;
-
+
WaypointList::iterator find(const UniqueID &x);
WaypointList::const_iterator find(const UniqueID &x)const;
- WaypointList::iterator find(const Time &x);
+ WaypointList::iterator find(const Time &x);
WaypointList::const_iterator find(const Time &x)const;
-
+
WaypointList::iterator find_next(const Time &x);
WaypointList::const_iterator find_next(const Time &x)const;
WaypointList::iterator find_prev(const Time &x);
int find(const Time& begin,const Time& end,std::vector<Waypoint*>& list);
void insert_time(const Time& location, const Time& delta);
-
+
protected:
ValueNode_Animated();
{
affine_combo<Real,float> mag_combo;
affine_combo<Angle,float> ang_combo;
-
+
Real mag(mag_combo(a.mag(),b.mag(),c));
Angle ang(ang_combo(Angle::tan(a[1],a[0]),Angle::tan(b[1],b[0]),c));
-
+
return Point( mag*Angle::cos(ang).get(),mag*Angle::sin(ang).get() );
}
synfig::convert_bline_to_segment_list(const ValueBase& bline)
{
std::vector<Segment> ret;
-
+
// std::vector<BLinePoint> list(bline.operator std::vector<BLinePoint>());
//std::vector<BLinePoint> list(bline);
std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end());
std::vector<BLinePoint>::const_iterator iter;
BLinePoint prev,first;
-
+
//start with prev = first and iter on the second...
-
+
if(list.empty()) return ValueBase(ret,bline.get_loop());
first = prev = list.front();
-
+
for(iter=++list.begin();iter!=list.end();++iter)
{
ret.push_back(
)
);
prev=*iter;
- }
+ }
if(bline.get_loop())
{
ret.push_back(
//std::vector<BLinePoint> list(bline);
std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end());
std::vector<BLinePoint>::const_iterator iter;
-
+
if(bline.empty())
return ValueBase(ValueBase::TYPE_LIST);
-
+
for(iter=list.begin();iter!=list.end();++iter)
ret.push_back(iter->get_width());
{
if(value.get_type()!=ValueBase::TYPE_LIST)
return 0;
-
+
ValueNode_BLine* value_node(new ValueNode_BLine());
if(!value.empty())
std::vector<BLinePoint>::const_iterator iter;
for(iter=bline_points.begin();iter!=bline_points.end();iter++)
- {
+ {
value_node->add(ValueNode::Handle(ValueNode_Composite::create(*iter)));
}
value_node->set_loop(value.get_loop());
// into a list of BLinePoints. We make an assumption
// that the segment list is continuous(sp), but not necessarily
// smooth.
-
+
value_node->set_loop(false);
// std::vector<Segment> segments(value.operator std::vector<Segment>());
// std::vector<Segment> segments(value);
std::vector<Segment>::const_iterator iter,last(segments.end());
--last;
ValueNode_Const::Handle prev,first;
-
+
for(iter=segments.begin();iter!=segments.end();iter++)
- {
+ {
#define PREV_POINT prev->get_value().get(BLinePoint())
#define FIRST_POINT first->get_value().get(BLinePoint())
#define CURR_POINT curr->get_value().get(BLinePoint())
prev=ValueNode_Const::create(ValueBase::TYPE_BLINEPOINT);
{
BLinePoint prev_point(PREV_POINT);
- prev_point.set_vertex(iter->p1);
+ prev_point.set_vertex(iter->p1);
prev_point.set_tangent1(iter->t1);
prev_point.set_width(0.01);
prev_point.set_origin(0.5);
}
first=prev;
value_node->add(ValueNode::Handle(prev));
-
+
}
if(iter==last && iter->p2.is_equal_to(FIRST_POINT.get_vertex()))
{
}
continue;
}
-
+
ValueNode_Const::Handle curr;
curr=ValueNode_Const::create(ValueBase::TYPE_BLINEPOINT);
{
BLinePoint curr_point(CURR_POINT);
- curr_point.set_vertex(iter->p2);
+ curr_point.set_vertex(iter->p2);
curr_point.set_tangent1(iter->t2);
curr_point.set_width(0.01);
curr_point.set_origin(0.5);
value_node->add(ValueNode::Handle(curr));
prev=curr;
}
-
+
}
break;
default:
break;
}
}
-
-
+
+
return value_node;
}
{
ValueNode_BLine::ListEntry ret;
-
+
synfig::BLinePoint prev,next;
int prev_i,next_i;
else
next_i=index;
prev_i=find_prev_valid_entry(index,time);
-
+
synfig::info("index=%d, next_i=%d, prev_i=%d",index,next_i,prev_i);
-
+
next=(*list[next_i].value_node)(time);
prev=(*list[prev_i].value_node)(time);
-
+
etl::hermite<Vector> curve(prev.get_vertex(),next.get_vertex(),prev.get_tangent2(),next.get_tangent1());
etl::derivative< etl::hermite<Vector> > deriv(curve);
bline_point.set_tangent2(bline_point.get_tangent1());
bline_point.set_split_tangent_flag(false);
bline_point.set_origin(origin);
-
+
ret.value_node=ValueNode_Composite::create(bline_point);
-
+
return ret;
}
ValueNode_BLine::operator()(Time t)const
{
std::vector<BLinePoint> ret_list;
-
+
std::vector<ListEntry>::const_iterator iter,first_iter;
bool first_flag(true);
bool rising;
int index(0);
float next_scale(1.0f);
-
+
BLinePoint prev,first;
first.set_origin(100.0f);
-
+
for(iter=list.begin();iter!=list.end();++iter,index++)
{
float amount(iter->amount_at_time(t,&rising));
-
+
assert(amount>=0.0f);
assert(amount<=1.0f);
-
+
if(amount==1.0f)
{
if(first_flag)
ret_list.push_back(first);
continue;
}
-
+
BLinePoint curr;
curr=(*iter->value_node)(t).get(prev);
-
+
if(next_scale!=1.0f)
{
ret_list.back().set_split_tangent_flag(true);
ret_list.push_back(curr);
}
-
+
prev=curr;
}
else
if(amount>0.0f)
{
std::vector<ListEntry>::const_iterator begin_iter,end_iter;
-
+
// This is where the interesting stuff happens
// We need to seek forward in the list to see what the next
// active point is
-
+
BLinePoint curr;
BLinePoint begin; // begin of dynamic group
BLinePoint end; // End of dynamic group
Time blend_time;
int dist_from_begin(0), dist_from_end(0);
BLinePoint ret;
-
+
Time begin_time;
Time end_time;
-
+
if(!rising)
{
try{ end_time=iter->find_prev(t)->get_time(); }
catch(...) { end_time=Time::end(); }
}
blend_time=begin_time;
- curr=(*iter->value_node)(end_time).get(curr);
+ curr=(*iter->value_node)(end_time).get(curr);
// curr=(*iter->value_node)(t).get(curr);
-
+
// Find "end" of dynamic group
end_iter=iter;
// for(++end_iter;begin_iter!=list.end();++end_iter)
end=(*end_iter->value_node)(blend_time).get(prev);
break;
}
-
+
// If we did not find an end of the dynamic group...
if(end_iter==list.end())
{
else
break;
}
-
+
--begin_iter;
dist_from_begin++;
-
+
if(begin_iter==iter)
break;
break;
}
}while(begin_iter!=iter);
-
+
// If we did not find a begin
if(begin.get_origin()==100.0f)
{
// begin=first;
}
}
-
+
etl::hermite<Vector> curve(begin.get_vertex(),end.get_vertex(),begin.get_tangent2(),end.get_tangent1());
etl::derivative< etl::hermite<Vector> > deriv(curve);
-
+
ret.set_vertex(curve(curr.get_origin()));
ret.set_width((end.get_width()-begin.get_width())*curr.get_origin()+begin.get_width());
ret.set_tangent1(deriv(curr.get_origin()));
ret.set_tangent2(deriv(curr.get_origin()));
-
+
float prev_tangent_scalar(1.0f);
float next_tangent_scalar(1.0f);
-
+
//synfig::info("index_%d:dist_from_begin=%d",index,dist_from_begin);
//synfig::info("index_%d:dist_from_end=%d",index,dist_from_end);
-
+
// If we are the next to the begin
if(begin_iter==--std::vector<ListEntry>::const_iterator(iter) || dist_from_begin==1)
{
else
{
float origin=curr.get_origin()-prev.get_origin();
- prev_tangent_scalar=(1.0f-origin)*amount+origin;
+ prev_tangent_scalar=(1.0f-origin)*amount+origin;
}
// If we are the next to the end
BLinePoint next;
next=((*(++std::vector<ListEntry>::const_iterator(iter))->value_node)(t).get(prev));
float origin=next.get_origin()-curr.get_origin();
- next_tangent_scalar=(1.0f-origin)*amount+origin;
+ next_tangent_scalar=(1.0f-origin)*amount+origin;
}
next_scale=next_tangent_scalar;
-
+
//ret.set_vertex((curr.get_vertex()-ret.get_vertex())*amount+ret.get_vertex());
if(false)
{
Point begin_cord_sys[2], begin_cord_origin;
Point end_cord_sys[2], end_cord_origin;
Point curr_cord_sys[2], curr_cord_origin;
-
+
{
const Point a((*end_iter->value_node)(begin_time).get(prev).get_vertex());
const Point b((*begin_iter->value_node)(begin_time).get(prev).get_vertex());
curr_cord_sys[0]=( b - a ).norm();
curr_cord_sys[1]=curr_cord_sys[0].perp();
}
-
+
/*
end_cord_origin=(*end_iter->value_node)(end_time).get(prev).get_vertex();
end_cord_sys[0]=(
end_cord_origin
).norm();
end_cord_sys[1]=end_cord_sys[0].perp();
-
+
curr_cord_origin=(*end_iter->value_node)(t).get(prev).get_vertex();
curr_cord_sys[0]=(
(*begin_iter->value_node)(t).get(prev).get_vertex() -
).norm();
curr_cord_sys[1]=curr_cord_sys[0].perp();
*/
-
+
// Convert start point
Point a;
Vector at1,at2;
a[0]=tmp*begin_cord_sys[0];
a[1]=tmp*begin_cord_sys[1];
#define COORD_SYS_RADIAL_TAN_INTERP 1
-
+
#ifdef COORD_SYS_RADIAL_TAN_INTERP
tmp=ret.get_tangent1()+ret.get_vertex()-begin_cord_origin;
at1[0]=tmp*begin_cord_sys[0];
at1[1]=tmp*begin_cord_sys[1];
-
+
if(curr.get_split_tangent_flag())
{
tmp=ret.get_tangent2()+ret.get_vertex()-begin_cord_origin;
}
#endif
}
-
+
// Convert finish point
Point b;
Vector bt1,bt2;
Point tmp(curr.get_vertex()-end_cord_origin);
b[0]=tmp*end_cord_sys[0];
b[1]=tmp*end_cord_sys[1];
-
+
#ifdef COORD_SYS_RADIAL_TAN_INTERP
tmp=curr.get_tangent1()+curr.get_vertex()-end_cord_origin;
bt1[0]=tmp*end_cord_sys[0];
}
#endif
}
-
+
// Convert current point
Point c;
Vector ct1,ct2;
#define INTERP_FUNCTION radial_interpolation
//#define INTERP_FUNCTION linear_interpolation
-
+
#ifdef COORD_SYS_RADIAL_TAN_INTERP
tmp=INTERP_FUNCTION(at1,bt1,amount);
ct1[0]=tmp*curr_cord_sys[0];
ct1[1]=tmp*curr_cord_sys[1];
ct1+=curr_cord_origin;
ct1-=c;
-
+
if(curr.get_split_tangent_flag())
{
tmp=INTERP_FUNCTION(at2,bt2,amount);
ret.set_split_tangent_flag(curr.get_split_tangent_flag());
if(ret.get_split_tangent_flag())
ret.set_tangent2(radial_interpolation(ret.get_tangent2(),curr.get_tangent2(),amount));
-#else
+#else
ret.set_tangent1(ct1);
ret.set_split_tangent_flag(curr.get_split_tangent_flag());
if(ret.get_split_tangent_flag())
ret.set_tangent2(ct2);
#endif
}
-
+
ret.set_origin(curr.get_origin());
ret.set_width((curr.get_width()-ret.get_width())*amount+ret.get_width());
-
+
// Handle the case where we are the first vertex
if(first_flag)
prev=ret;
}
}
-
+
if(next_scale!=1.0f)
{
ret_list.back().set_split_tangent_flag(true);
);
}
*/
-
+
if(list.empty())
synfig::warning(string("ValueNode_BLine::operator()():")+_("No entries in list"));
else
{
assert(i>=0 && (unsigned)i<list.size());
return etl::strprintf(_("Vertex %03d"),i+1);
-}
+}
ValueNode*
ValueNode_BLine::clone(const GUID& deriv_guid)const
ValueNode_BLine* ret=new ValueNode_BLine();
ret->set_guid(get_guid()^deriv_guid);
-
+
std::vector<ListEntry>::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
}
}
ret->set_loop(get_loop());
-
+
return ret;
}
//! Converts a list of bline points into a list of widths
ValueBase convert_bline_to_width_list(const ValueBase &bline);
-
+
/*! \class ValueNode_BLine
** \brief \writeme
*/
typedef etl::handle<ValueNode_BLine> Handle;
typedef etl::handle<const ValueNode_BLine> ConstHandle;
-
+
ValueNode_BLine();
public:
-
-
+
+
virtual ValueBase operator()(Time t)const;
virtual ~ValueNode_BLine();
virtual String get_local_name()const;
virtual ValueNode* clone(const GUID& deriv_guid=GUID())const;
-
+
virtual ListEntry create_list_entry(int index, Time time=0, Real origin=0.5);
protected:
-
+
LinkableValueNode* create_new()const;
public:
}
default:
assert(0);
- throw Exception::BadType(ValueBase::type_name(get_type()));
+ throw Exception::BadType(ValueBase::type_name(get_type()));
}
}
{
return new ValueNode_Composite(value);
}
-
+
LinkableValueNode*
ValueNode_Composite::create_new()const
{
{
assert(i>=0);
assert(i<6);
-
+
if(PlaceholderValueNode::Handle::cast_dynamic(x))
{
components[i]=x;
return true;
}
break;
-
+
case ValueBase::TYPE_SEGMENT:
assert(i<4);
if(x->get_type()==ValueBase(Point()).get_type() || PlaceholderValueNode::Handle::cast_dynamic(x))
return true;
}
break;
-
+
default:
break;
}
- return false;
+ return false;
}
ValueNode::LooseHandle
return _("Blue");
else if(i==3)
return _("Alpha");
-
+
case ValueBase::TYPE_SEGMENT:
if(i==0)
return _("Vertex 1");
default:
break;
}
- return etl::strprintf(_("C%d"),i+1);
-}
+ return etl::strprintf(_("C%d"),i+1);
+}
String
{
assert(i>=0 && i<5);
return strprintf("c%d",i);
-}
+}
int
ValueNode_Composite::get_link_index_from_name(const String &name)const
return 4;
if(name=="t2")
return 5;
- default:
+ default:
break;
}
{
ValueNode::RHandle components[6];
ValueNode_Composite(const ValueBase &value);
-
+
public:
typedef etl::handle<ValueNode_Composite> Handle;
typedef etl::handle<const ValueNode_Composite> ConstHandle;
virtual String get_name()const;
virtual String get_local_name()const;
virtual int get_link_index_from_name(const String &name)const;
-
+
protected:
virtual bool set_link_vfunc(int i,ValueNode::Handle x);
-
+
LinkableValueNode* create_new()const;
public:
private:
ValueBase value;
-
+
ValueNode_Const();
ValueNode_Const(const ValueBase &x);
public:
-
+
virtual ValueBase operator()(Time t)const;
virtual ~ValueNode_Const();
const ValueBase &get_value()const;
ValueBase &get_value();
void set_value(const ValueBase &data);
-
+
virtual String get_name()const;
virtual String get_local_name()const;
virtual ValueNode* clone(const GUID& deriv_guid=GUID())const;
-
+
public:
static ValueNode_Const* create(const ValueBase &x=ValueBase());
ValueNode_DynamicList::ListEntry::add(Time time, bool status, int priority)
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
-
+
//! \optimize
Activepoint ap(time,status,priority);
ap.set_parent_index(get_index());
timing_info.push_back(ap);
iterator iter(--iterator(timing_info.end()));
timing_info.sort();
-
+
return iter;
}
ValueNode_DynamicList::ListEntry::add(const Activepoint &x)
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
-
+
//! \optimize
Activepoint ap(x);
ap.set_parent_index(get_index());
timing_info.push_back(ap);
iterator iter(--iterator(timing_info.end()));
timing_info.sort();
-
+
return iter;
}
ValueNode_DynamicList::reindex()
{
int i(0);
-
+
std::vector<ListEntry>::iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
iter2->set_parent_index(i);
iter2->set_parent_value_node(this);
}
- iter->index=i;
+ iter->index=i;
iter->set_parent_value_node(this);
}
}
ValueNode_DynamicList::create_list_entry(int index, Time time, Real origin)
{
ValueNode_DynamicList::ListEntry ret;
-
-
+
+
synfig::ValueBase prev,next;
index=index%link_count();
assert(index>=0);
-
+
ret.index=index;
ret.set_parent_value_node(this);
-
+
next=(*list[index].value_node)(time);
-
+
if(index!=0)
prev=(*list[index-1].value_node)(time);
else
prev=next;
}
}
-
-
+
+
switch(get_contained_type())
{
case ValueBase::TYPE_VECTOR:
break;
}
-
+
return ret;
}
ValueNode_DynamicList::ListEntry::find(const Time& x)
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
ActivepointList::iterator iter;
for(iter=timing_info.begin();iter!=timing_info.end();++iter)
if(iter->time==x)
return iter;
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find():"+x.get_string());
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find():"+x.get_string());
}
ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
ValueNode_DynamicList::ListEntry::find(const Time& x)const
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
ActivepointList::const_iterator iter;
for(iter=timing_info.begin();iter!=timing_info.end();++iter)
if(iter->time==x)
return iter;
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find()const:"+x.get_string());
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find()const:"+x.get_string());
}
ValueNode_DynamicList::ListEntry::ActivepointList::iterator
ValueNode_DynamicList::ListEntry::find_next(const Time& x)
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
ActivepointList::iterator iter;
for(iter=timing_info.begin();iter!=timing_info.end();++iter)
if(iter->time>x)
return iter;
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next():"+x.get_string());
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next():"+x.get_string());
}
ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
ValueNode_DynamicList::ListEntry::find_next(const Time& x)const
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
ActivepointList::const_iterator iter;
for(iter=timing_info.begin();iter!=timing_info.end();++iter)
if(iter->time>x)
return iter;
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next()const:"+x.get_string());
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next()const:"+x.get_string());
}
ValueNode_DynamicList::ListEntry::ActivepointList::iterator
ValueNode_DynamicList::ListEntry::find_prev(const Time& x)
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
ActivepointList::iterator iter;
iter=timing_info.end();
do
}
while(iter!=timing_info.begin());
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev():"+x.get_string());
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev():"+x.get_string());
}
ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
ValueNode_DynamicList::ListEntry::find_prev(const Time& x)const
{
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
ActivepointList::const_iterator iter;
iter=timing_info.end();
do
}
while(iter!=timing_info.begin());
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev()const:"+x.get_string());
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev()const:"+x.get_string());
}
int
{
Time curr_time(begin);
int ret(0);
-
+
// try to grab first waypoint
try
{
ret++;
}
catch(...) { }
-
+
try
{
ActivepointList::iterator iter;
}
}
catch(...) { }
-
+
return ret;
}
{
typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
if(timing_info.empty())
return 1.0f;
-
+
try
{
ActivepointList::const_iterator iter;
try { prev_iter=find_prev(t); }
catch(...) { return find_next(t)->state?1.0f:0.0f; }
-
+
try { next_iter=find_next(t); }
catch(...) { return prev_iter->state?1.0f:0.0f; }
-
+
if(next_iter->state==prev_iter->state)
return next_iter->state?1.0f:0.0f;
-
+
if(rising)*rising=next_iter->state;
if(next_iter->state==true)
ValueNode_DynamicList::ListEntry::new_activepoint_at_time(const Time& time)const
{
Activepoint activepoint;
-
+
activepoint.set_state(status_at_time(time));
activepoint.set_priority(0);
-
+
return activepoint;
}
{
typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
+
ActivepointList::const_iterator entry_iter;
ActivepointList::const_iterator prev_iter;
bool state(true);
}
if(entry_iter->time>t)
break;
-
+
}
prev_iter=entry_iter;
prev_iter--;
-
+
// ie:
//
// |-------|---t---|-------|
// prev_iter^ ^entry_iter
-
+
if(entry_iter==timing_info.end())
{
state=prev_iter->state;
}
else
{
- state=prev_iter->state;
- }
+ state=prev_iter->state;
+ }
}
}
return state;
{
ListEntry list_entry(value_node);
list_entry.timing_info.size();
-
+
if(index<0 || index>=(int)list.size())
{
list.push_back(list_entry);
ValueNode_DynamicList::erase(const ValueNode::Handle &value_node_)
{
ValueNode::Handle value_node(value_node_);
-
+
assert(value_node);
if(!value_node)
throw String("ValueNode_DynamicList::erase(): Passed bad value node");
-
+
std::vector<ListEntry>::iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
if(iter->value_node==value_node)
if(value_list.empty())
return 0;
-
+
ValueNode_DynamicList* value_node(new ValueNode_DynamicList(value_list.front().get_type()));
-
+
for(iter=value_list.begin();iter!=value_list.end();++iter)
{
ValueNode::Handle item(ValueNode_Const::create(*iter));
for(iter=list.begin();iter!=list.end();++iter)
{
bool state(iter->status_at_time(t));
-
+
if(state)
{
if(iter->value_node->get_type()==container_type)
}
}
}
-
+
if(list.empty())
synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in list"));
else
{
assert(i>=0 && (unsigned)i<list.size());
return etl::strprintf(_("Item %03d"),i+1);
-}
+}
ValueNode*
ValueNode_DynamicList::clone(const GUID& deriv_guid)const
if(iter->value_node->is_exported())
ret->add(*iter);
else
- {
+ {
ListEntry list_entry(*iter);
//list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
//if(!list_entry.value_node)
ValueNode_DynamicList::find_next_valid_entry(int orig_item, Time t)const
{
int curr_item;
-
+
for(curr_item=orig_item+1;curr_item!=orig_item;curr_item++)
{
if(curr_item==(int)list.size())
ValueNode_DynamicList::find_prev_valid_entry(int orig_item, Time t)const
{
int curr_item;
-
+
for(curr_item=orig_item-1;curr_item!=orig_item;curr_item--)
{
if(curr_item==-1)
{
synfig::ActivepointList::const_iterator j = timing_info.begin(),
end = timing_info.end();
-
+
//must remerge with all the other values because we don't know if we've changed...
times = value_node->get_times();
-
+
for(; j != end; ++j)
{
TimePoint t;
times.insert(t);
}
-
+
return times;
}
{
//add in the active points
int size = list.size();
-
+
//rebuild all the info...
for(int i = 0; i < size; ++i)
{
{
findresult f;
f.second = false;
-
+
f.first = std::find(timing_info.begin(),timing_info.end(),x);
-
+
if(f.first != timing_info.end())
{
f.second = true;
}
-
+
return f;
}
{
const_findresult f;
f.second = false;
-
+
f.first = std::find(timing_info.begin(),timing_info.end(),x);
-
+
if(f.first != timing_info.end())
{
f.second = true;
}
-
+
return f;
}
{
findresult f;
f.second = false;
-
+
f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
-
+
if(f.first != timing_info.end())
{
f.second = true;
}
-
+
return f;
}
{
const_findresult f;
f.second = false;
-
+
f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
-
+
if(f.first != timing_info.end())
{
f.second = true;
}
-
+
return f;
}
try
{
ListEntry& item(*iter);
-
+
ActivepointList::iterator iter(item.find_next(location));
for(;iter!=item.timing_info.end();++iter)
{
namespace synfig {
class ValueNode_BLine;
-
+
/*! \class ValueNode_DynamicList
** \brief Animated List ValueNode
**
** This ValueNode was originaly set up to have a list
** of ValueNodes and their associated "on" and "off" points.
** ie: Any time that was directly after an "on" point,
-** the item would be "on", and any time that was directly
+** the item would be "on", and any time that was directly
** after an "off" point would be "off". This is pretty intuitive.
** However, it does have it's problems.
**
class ValueNode_DynamicList : public LinkableValueNode
{
public:
-
+
/*! \class ListEntry
** \brief Contains a potential list item, and associated timing information
**
friend class ValueNode_BLine;
public:
typedef synfig::Activepoint Activepoint;
-
+
typedef std::list<Activepoint> ActivepointList;
-
+
typedef std::pair<ActivepointList::iterator,bool> findresult;
typedef std::pair<ActivepointList::const_iterator,bool> const_findresult;
-
+
private:
mutable Node::time_set times;
public:
ValueNode::RHandle value_node;
-
+
ActivepointList timing_info;
-
+
private:
int index;
etl::loose_handle<ValueNode> parent_;
- void set_parent_value_node(const etl::loose_handle<ValueNode> &x) { parent_=x; }
+ void set_parent_value_node(const etl::loose_handle<ValueNode> &x) { parent_=x; }
public:
int get_index()const { return index; }
-
-
+
+
bool status_at_time(const Time &x)const;
float amount_at_time(const Time &x, bool *rising=0)const;
ActivepointList::iterator add(Time time, bool status, int priority=0);
ActivepointList::iterator add(const Activepoint &x);
-
+
findresult find_uid(const UniqueID& x);
const_findresult find_uid(const UniqueID& x)const;
-
+
findresult find_time(const Time& x);
const_findresult find_time(const Time& x)const;
-
+
ActivepointList::iterator find(const UniqueID& x);
ActivepointList::const_iterator find(const UniqueID& x)const;
ActivepointList::iterator find(const Time& x);
ActivepointList::iterator add(Time time)
{ return add(time, status_at_time(time)); }
- void erase(const UniqueID& x);
-
+ void erase(const UniqueID& x);
+
int find(const Time& begin,const Time& end,std::vector<Activepoint*>& list);
-
+
const synfig::Node::time_set &get_times() const;
const etl::loose_handle<ValueNode> &get_parent_value_node()const { return parent_; }
ListEntry(const ValueNode::Handle &value_node);
ListEntry(const ValueNode::Handle &value_node,Time begin, Time end);
}; // END of struct ValueNode_DynamicList::ListEntry
-
+
typedef etl::handle<ValueNode_DynamicList> Handle;
typedef etl::handle<const ValueNode_DynamicList> ConstHandle;
std::vector<ListEntry> list;
public:
-
+
void add(const ValueNode::Handle &value_node, int index=-1);
void add(const ListEntry &value_node, int index=-1);
void erase(const ValueNode::Handle &value_node);
int find_next_valid_entry(int x, Time t)const;
int find_prev_valid_entry(int x, Time t)const;
-
+
virtual ValueNode::LooseHandle get_link_vfunc(int i)const;
virtual int link_count()const;
virtual ListEntry create_list_entry(int index, Time time=0, Real origin=0.5);
protected:
-
+
virtual bool set_link_vfunc(int i,ValueNode::Handle x);
LinkableValueNode* create_new()const;
if(id!=ValueBase::TYPE_GRADIENT)
{
assert(0);
- throw runtime_error("synfig::ValueNode_GradientRotate:Bad type "+ValueBase::type_name(id));
- }
+ throw runtime_error("synfig::ValueNode_GradientRotate:Bad type "+ValueBase::type_name(id));
+ }
ValueNode_GradientRotate* value_node=new ValueNode_GradientRotate();
value_node->set_gradient(ValueNode_Const::create(x.get(Gradient())));
assert(value_node->get_type()==id);
-
+
return value_node;
}
Gradient::iterator iter;
for(iter=gradient.begin();iter!=gradient.end();++iter)
iter->pos+=offset;
-
+
return gradient;
}
return _("Offset");
}
return String();
-}
+}
String
ValueNode_GradientRotate::link_name(int i)const
return "offset";
}
return String();
-}
+}
int
ValueNode_GradientRotate::get_link_index_from_name(const String &name)const
{
typedef etl::handle<ValueNode_GradientRotate> Handle;
typedef etl::handle<const ValueNode_GradientRotate> ConstHandle;
-
+
protected:
ValueNode_GradientRotate();
{
return _("Linear");
}
-
+
bool
ValueNode_Linear::check_type(ValueBase::Type type)
{
return 0;
if(name=="offset")
return 1;
-
+
throw Exception::BadLinkName(name);
}
{
ValueNode::RHandle m_;
ValueNode::RHandle b_;
-
+
ValueNode_Linear(const ValueBase::Type &x);
public:
break;
default:
assert(0);
- throw Exception::BadType(ValueBase::type_name(get_type()));
+ throw Exception::BadType(ValueBase::type_name(get_type()));
}
}
{
return new ValueNode_RadialComposite(value);
}
-
+
LinkableValueNode*
ValueNode_RadialComposite::create_new()const
{
{
assert(i>=0);
assert(i<6);
-
+
if(PlaceholderValueNode::Handle::cast_dynamic(x))
{
components[i]=x;
components[i]=x;
return true;
break;
-
-
+
+
default:
break;
}
- return false;
+ return false;
}
ValueNode::LooseHandle
else if(i==3)
return _("Alpha");
break;
-
+
default:
break;
}
- return etl::strprintf(_("C%d"),i+1);
-}
+ return etl::strprintf(_("C%d"),i+1);
+}
String
{
assert(i>=0 && i<5);
return strprintf("c%d",i);
-}
+}
int
ValueNode_RadialComposite::get_link_index_from_name(const String &name)const
return 0;
if(name[0]=='t')
return 1;
- default:
+ default:
break;
}
{
ValueNode::RHandle components[6];
ValueNode_RadialComposite(const ValueBase &value);
-
+
public:
typedef etl::handle<ValueNode_RadialComposite> Handle;
typedef etl::handle<const ValueNode_RadialComposite> ConstHandle;
virtual String get_name()const;
virtual String get_local_name()const;
virtual int get_link_index_from_name(const String &name)const;
-
+
protected:
virtual bool set_link_vfunc(int i,ValueNode::Handle x);
-
+
LinkableValueNode* create_new()const;
public:
signal_child_changed()(i);signal_value_changed()();
return true;
}
-
+
ValueNode::LooseHandle
ValueNode_Reference::get_link_vfunc(int i)const
{
{
assert(i==0);
return _("Link");
-}
+}
String
ValueNode_Reference::link_name(int i)const
protected:
virtual bool set_link_vfunc(int i,ValueNode::Handle x);
-
+
LinkableValueNode* create_new()const;
public:
break;
default:
assert(0);
- throw runtime_error("synfig::ValueNode_Scale:Bad type "+ValueBase::type_name(x.get_type()));
+ throw runtime_error("synfig::ValueNode_Scale:Bad type "+ValueBase::type_name(x.get_type()));
}
assert(value_node);
assert(value_node->get_type()==x.get_type());
-
+
return value_node;
}
{
if(!(i==0 || i==1))
return false;
-
+
if(i==0 && !set_value_node(x))
return false;
else
if(i==1 && !set_scalar(x))
return false;
-
+
signal_child_changed()(i);signal_value_changed()();
return true;
else if(i==1)
return _("Scalar");
return String();
-}
+}
String
ValueNode_Scale::link_name(int i)const
return 0;
if(name=="scalar")
return 1;
-
+
throw Exception::BadLinkName(name);
}
{
typedef etl::handle<ValueNode_Scale> Handle;
typedef etl::handle<const ValueNode_Scale> ConstHandle;
-
+
private:
ValueNode::RHandle value_node;
ValueNode::RHandle scalar;
virtual ValueBase operator()(Time t)const;
virtual String get_name()const;
-
+
virtual String get_local_name()const;
virtual String link_local_name(int i)const;
protected:
virtual bool set_link_vfunc(int i,ValueNode::Handle x);
-
+
virtual LinkableValueNode* create_new()const;
public:
{
if(x!=ValueBase::TYPE_VECTOR)
throw Exception::BadType(ValueBase::type_name(x));
-
+
segment_=ValueNode_Composite::create(ValueBase::TYPE_SEGMENT);
amount_=ValueNode_Const::create(Real(0.5));
}
etl::hermite<Vector> curve(segment.p1,segment.p2,segment.t1,segment.t2);
etl::derivative< etl::hermite<Vector> > deriv(curve);
-
+
#ifdef ETL_FIXED_DERIVATIVE
return deriv((*amount_)(t).get(Real()))*(0.5);
#else
return deriv((*amount_)(t).get(Real()))*(-0.5);
#endif
-
+
}
{
return _("SegCalcTangent");
}
-
+
bool
ValueNode_SegCalcTangent::check_type(ValueBase::Type type)
{
return 0;
if(name=="amount")
return 1;
-
+
throw Exception::BadLinkName(name);
}
{
ValueNode::RHandle segment_;
ValueNode::RHandle amount_;
-
+
ValueNode_SegCalcTangent(const ValueBase::Type &x=ValueBase::TYPE_VECTOR);
public:
{
if(x!=ValueBase::TYPE_VECTOR)
throw Exception::BadType(ValueBase::type_name(x));
-
+
segment_=ValueNode_Composite::create(ValueBase::TYPE_SEGMENT);
amount_=ValueNode_Const::create(Real(0.5));
-
+
}
ValueNode_SegCalcVertex*
Segment segment((*segment_)(t).get(Segment()));
etl::hermite<Vector> curve(segment.p1,segment.p2,segment.t1,segment.t2);
-
+
return curve((*amount_)(t).get(Real()));
}
{
return _("SegCalcVertex");
}
-
+
bool
ValueNode_SegCalcVertex::check_type(ValueBase::Type type)
{
return 0;
if(name=="amount")
return 1;
-
+
throw Exception::BadLinkName(name);
}
{
ValueNode::RHandle segment_;
ValueNode::RHandle amount_;
-
+
ValueNode_SegCalcVertex(const ValueBase::Type &x=ValueBase::TYPE_VECTOR);
public:
{
return _("Sine");
}
-
+
bool
ValueNode_Sine::check_type(ValueBase::Type type)
{
return 0;
if(name=="amp")
return 1;
-
+
throw Exception::BadLinkName(name);
}
{
ValueNode::RHandle angle_;
ValueNode::RHandle amp_;
-
+
ValueNode_Sine(const ValueBase::Type &x);
public:
ValueNode_Stripes::create(const ValueBase& x)
{
ValueBase::Type id(x.get_type());
-
+
if(id!=ValueBase::TYPE_GRADIENT)
{
assert(0);
- throw runtime_error("synfig::ValueNode_Stripes:Bad type "+ValueBase::type_name(id));
- }
+ throw runtime_error("synfig::ValueNode_Stripes:Bad type "+ValueBase::type_name(id));
+ }
ValueNode_Stripes* value_node=new ValueNode_Stripes();
assert(value_node->get_type()==id);
-
+
return value_node;
}
synfig::ValueBase
synfig::ValueNode_Stripes::operator()(Time t)const
{
- const int total((*stripes_)(t).get(int()));
+ const int total((*stripes_)(t).get(int()));
int i;
Gradient ret;
const Color color1((*color1_)(t).get(Color()));
const Color color2((*color2_)(t).get(Color()));
const float width(max(0.0,min(1.0,(*width_)(t).get(Real()))));
-
+
const float stripe_width_a(width/total);
const float stripe_width_b((1.0-width)/total);
-
+
for(i=0;i<total;i++)
{
float pos(float(i)/total+stripe_width_b/2);
return _("Width");
}
return String();
-}
+}
String
ValueNode_Stripes::link_name(int i)const
return "width";
}
return String();
-}
+}
int
ValueNode_Stripes::get_link_index_from_name(const String &name)const
{
typedef etl::handle<ValueNode_Stripes> Handle;
typedef etl::handle<const ValueNode_Stripes> ConstHandle;
-
+
protected:
ValueNode_Stripes();
ValueNode_Subtract::create(const ValueBase& x)
{
ValueBase::Type id(x.get_type());
-
+
ValueNode_Subtract* value_node=new ValueNode_Subtract();
switch(id)
{
break;
default:
assert(0);
- throw runtime_error("synfig::ValueNode_Subtract:Bad type "+ValueBase::type_name(id));
+ throw runtime_error("synfig::ValueNode_Subtract:Bad type "+ValueBase::type_name(id));
}
assert(value_node->get_type()==id);
-
+
return value_node;
}
synfig::ValueNode_Subtract::set_lhs(ValueNode::Handle a)
{
ref_a=a;
-
+
if(PlaceholderValueNode::Handle::cast_dynamic(a))
return true;
-
+
if(!ref_a || !ref_b)
set_type(ValueBase::TYPE_NIL);
else
return _("Scalar");
}
return String();
-}
+}
String
ValueNode_Subtract::link_name(int i)const
return "scalar";
}
return String();
-}
+}
int
ValueNode_Subtract::get_link_index_from_name(const String &name)const
bool
ValueNode_Subtract::check_type(ValueBase::Type type)
{
- return type==ValueBase::TYPE_VECTOR
+ return type==ValueBase::TYPE_VECTOR
|| type==ValueBase::TYPE_REAL
|| type==ValueBase::TYPE_INTEGER
|| type==ValueBase::TYPE_COLOR
{
typedef etl::handle<ValueNode_Subtract> Handle;
typedef etl::handle<const ValueNode_Subtract> ConstHandle;
-
+
protected:
ValueNode_Subtract();
if(t>swptime)
return (*after)(t);
-
+
if(t<=swptime && t>swptime-swplength)
{
Real amount=(swptime-t)/swplength;
// if amount==0.0, then we are after
// if amount==1.0, then we are before
-
+
switch(get_type())
{
case ValueBase::TYPE_REAL:
return _("Swap Duration");
}
return 0;
-}
+}
String
ValueNode_TimedSwap::link_name(int i)const
return "length";
}
return 0;
-}
+}
int
ValueNode_TimedSwap::get_link_index_from_name(const String &name)const
{
typedef etl::handle<ValueNode_TimedSwap> Handle;
typedef etl::handle<const ValueNode_TimedSwap> ConstHandle;
-
+
private:
ValueNode::RHandle before;
virtual ValueBase operator()(Time t)const;
- virtual String get_name()const;
+ virtual String get_name()const;
virtual String get_local_name()const;
// static bool check_type(const ValueBase::Type &type);
protected:
-
+
virtual LinkableValueNode* create_new()const;
public:
if(id!=ValueBase::TYPE_GRADIENT)
{
assert(0);
- throw runtime_error("synfig::ValueNode_TwoTone:Bad type "+ValueBase::type_name(id));
- }
+ throw runtime_error("synfig::ValueNode_TwoTone:Bad type "+ValueBase::type_name(id));
+ }
ValueNode_TwoTone* value_node=new ValueNode_TwoTone();
assert(value_node->get_type()==id);
-
+
return value_node;
}
return _("Color2");
}
return String();
-}
+}
String
ValueNode_TwoTone::link_name(int i)const
return "color2";
}
return String();
-}
+}
int
ValueNode_TwoTone::get_link_index_from_name(const String &name)const
{
typedef etl::handle<ValueNode_TwoTone> Handle;
typedef etl::handle<const ValueNode_TwoTone> ConstHandle;
-
+
protected:
ValueNode_TwoTone();
Vector(const value_type &x, const value_type &y):_x(x),_y(y) { };
bool is_valid()const { return !(isnan(_x) || isnan(_y)); }
-
+
value_type &
operator[](const int& i)
{ return (&_x)[i] ; }
const value_type &
operator[](const int& i) const
{ return (&_x)[i] ; }
-
+
const Vector &
operator+=(const Vector &rhs)
{
_y+=rhs._y;
return *this;
}
-
+
const Vector &
operator-=(const Vector &rhs)
{
_y-=rhs._y;
return *this;
}
-
+
const Vector &
operator*=(const value_type &rhs)
{
_y*=rhs;
return *this;
}
-
+
const Vector &
operator/=(const value_type &rhs)
{
_y*=tmp;
return *this;
}
-
+
Vector
operator+(const Vector &rhs)const
{ return Vector(*this)+=rhs; }
bool
operator==(const Vector &rhs)const
{ return _x==rhs._x && _y==rhs._y; }
-
+
bool
operator!=(const Vector &rhs)const
{ return _y!=rhs._y || _x!=rhs._x; }
-
+
//! Returns the squared magnitude of the vector
value_type mag_squared()const
{ return _x*_x+_y*_y; }
-
+
//! Returns the magnitude of the vector
value_type mag()const
{ return sqrt(mag_squared()); }
//! Returns a perpendicular version of the vector
Vector perp()const
{ return Vector(_y,-_x); }
-
+
bool is_equal_to(const Vector& rhs)const
{
static const value_type epsilon(0.0000000000001);
// return (_x>rhs._x)?_x-rhs._x<=epsilon:rhs._x-_x<=epsilon && (_y>rhs._y)?_y-rhs._y<=epsilon:rhs._y-_y<=epsilon;
return (*this-rhs).mag_squared()<=epsilon;
}
-
+
static const Vector zero() { return Vector(0,0); }
};
value_type a,b,c,d;
protected:
- affine_combo<value_type,time_type> affine_func;
+ affine_combo<value_type,time_type> affine_func;
public:
bezier_base() { }
const value_type &a, const value_type &b, const value_type &c, const value_type &d,
const time_type &r=0.0, const time_type &s=1.0):
a(a),b(b),c(c),d(d) { set_rs(r,s); sync(); }
-
+
void sync()
{
bezier_x[0]=a[0],bezier_y[0]=a[1];
{
return synfig::Vector(bezier_x(t),bezier_y(t));
}
-
+
void evaluate(time_type t, value_type &f, value_type &df) const
{
t=(t-get_r())/get_dt();
-
+
const value_type p1 = affine_func(
affine_func(a,b,t),
affine_func(b,c,t)
affine_func(b,c,t),
affine_func(c,d,t)
,t);
-
+
f = affine_func(p1,p2,t);
df = (p2-p1)*3;
}
/* === C L A S S E S & S T R U C T S ======================================= */
-namespace synfig {
+namespace synfig {
class ValueNode;
class GUID;
-
-
+
+
/*! \class Waypoint
** \brief \writeme
*/
class Model
{
friend class Waypoint;
-
+
int priority;
Interpolation before;
Interpolation after;
Real continuity;
Real bias;
Real temporal_tension;
-
+
bool priority_flag,before_flag,after_flag,tension_flag,continuity_flag,bias_flag,temporal_tension_flag;
-
+
public:
Model():
priority_flag(false),
continuity_flag(false),
bias_flag(false),
temporal_tension_flag(false) { }
-
+
Interpolation get_before()const { return before; }
void set_before(Interpolation x) { before=x; before_flag=true;}
-
+
Interpolation get_after()const { return after; }
void set_after(Interpolation x) { after=x; after_flag=true;}
-
+
const Real &get_tension()const { return tension; }
void set_tension(const Real &x) { tension=x; tension_flag=true;}
-
+
const Real &get_continuity()const { return continuity; }
void set_continuity(const Real &x) { continuity=x; continuity_flag=true;}
-
+
const Real &get_bias()const { return bias; }
void set_bias(const Real &x) { bias=x; bias_flag=true;}
const Real &get_temporal_tension()const { return temporal_tension; }
void set_temporal_tension(const Real &x) { temporal_tension=x; temporal_tension_flag=true;}
-
+
int get_priority()const { return priority; }
- void set_priority(int x) { priority=x; priority_flag=true;}
+ void set_priority(int x) { priority=x; priority_flag=true;}
#define FLAG_MACRO(x) bool get_##x##_flag()const { return x##_flag; } void set_##x##_flag(bool y) { x##_flag=y; }
FLAG_MACRO(priority)
FLAG_MACRO(bias)
FLAG_MACRO(temporal_tension)
#undef FLAG_MACRO
-
+
void reset()
{
priority_flag=false;
bias_flag=false;
temporal_tension_flag=false;
}
-
+
bool is_trivial()const
{
return !(
);
}
};
-
+
/*
-- ** -- D A T A -------------------------------------------------------------
*/
-
+
private:
-
+
int priority_;
etl::loose_handle<ValueNode> parent_;
Interpolation before, after;
-
+
etl::rhandle<ValueNode> value_node;
Time time;
-
+
// The following are for the INTERPOLATION_TCB type
Real tension;
Real continuity;
// The following are for the INTERPOLATION_MANUAL type
ValueBase cpoint_before,cpoint_after;
-
+
float time_tension;
-
+
/*
-- ** -- C O N S T R U C T O R S ---------------------------------------------
*/
Waypoint(ValueBase value, Time time);
Waypoint(etl::handle<ValueNode> value_node, Time time);
-
+
Waypoint();
/*
ValueBase get_value()const;
ValueBase get_value(const Time &t)const;
void set_value(const ValueBase &x);
-
+
const etl::rhandle<ValueNode> &get_value_node()const { return value_node; }
void set_value_node(const etl::handle<ValueNode> &x);
-
+
const Real &get_tension()const { return tension; }
void set_tension(const Real &x) { tension=x; }
const etl::loose_handle<ValueNode> &get_parent_value_node()const { return parent_; }
void set_parent_value_node(const etl::loose_handle<ValueNode> &x) { parent_=x; }
-
+
bool is_static()const;
float get_time_tension()const { return time_tension; }
void set_time_tension(const float& x) { time_tension=x; }
float get_temporal_tension()const { return time_tension; }
void set_temporal_tension(const float& x) { time_tension=x; }
-
+
bool operator<(const Waypoint &rhs)const
{ return time<rhs.time; }
-
+
bool operator<(const Time &rhs)const
{ return time.is_less_than(rhs); }
bool operator>(const Time &rhs)const
{ return time.is_more_than(rhs); }
-
+
bool operator==(const Time &rhs)const
{ return time.is_equal(rhs); }
bool operator!=(const Time &rhs)const
{ return !time.is_equal(rhs); }
-
+
bool operator==(const UniqueID &rhs)const
{ return get_uid()==rhs.get_uid(); }
bool operator!=(const UniqueID &rhs)const
SYNFIGTOOL_FILENOTFOUND =1,
SYNFIGTOOL_BORRED =2,
SYNFIGTOOL_HELP =3,
- SYNFIGTOOL_UNKNOWNARGUMENT =4,
- SYNFIGTOOL_UNKNOWNERROR =5,
- SYNFIGTOOL_INVALIDTARGET =6,
- SYNFIGTOOL_RENDERFAILURE =7,
+ SYNFIGTOOL_UNKNOWNARGUMENT =4,
+ SYNFIGTOOL_UNKNOWNERROR =5,
+ SYNFIGTOOL_INVALIDTARGET =6,
+ SYNFIGTOOL_RENDERFAILURE =7,
SYNFIGTOOL_BLANK =8,
SYNFIGTOOL_BADVERSION =9,
SYNFIGTOOL_MISSINGARGUMENT =10
class Progress : public synfig::ProgressCallback
{
const char *program;
-
+
public:
-
+
Progress(const char *name):program(name) { }
-
+
virtual bool
task(const String &task)
{
class RenderProgress : public synfig::ProgressCallback
{
string taskname;
-
+
etl::clock clk;
int clk_scanline; // The scanline at which the clock was reset
etl::clock clk2;
- float last_time;
+ float last_time;
public:
-
+
RenderProgress():clk_scanline(0), last_time(0) { }
-
+
virtual bool
task(const String &thetask)
{
if(clk2()<0.2)
return true;
clk2.reset();
-
+
if(scanline)
seconds=(int)time+1;
else
clk.reset();
clk_scanline=scanline;
}
-
+
if(seconds<0)
{
clk.reset();
days++,hours-=24;
while(days>=7)
weeks++,days-=7;
-
+
cerr<<taskname<<": "<<_("Line")<<" "<<scanline<<_(" of ")<<h<<" -- ";
//cerr<<time/(h-clk_scanline)<<" ";
/*
{
//cerr<<"reset"<<endl;
clk.reset();
- clk_scanline=scanline;
+ clk_scanline=scanline;
}
-
+
if(weeks)
cerr<<weeks<<"w ";
if(days)
cerr<<minutes<<"m ";
if(seconds)
cerr<<seconds<<"s ";
-
+
cerr<<" \r";
}
else
{
String filename;
String outfilename;
-
+
RendDesc desc;
Canvas::Handle root;
Canvas::Handle canvas;
Target::Handle target;
-
+
int quality;
bool sifout;
};
cerr<<strprintf(" %s %s %s",flag, arg, spaces+strlen(arg)+strlen(flag)+1)+description<<endl;
else
cerr<<strprintf(" %s %s",flag,spaces+strlen(flag))+description<<endl;
-
+
}
};
cerr<<_("syntax: ")<<progname<<" [DEFAULT OPTIONS] ([SIF FILE] [SPECIFIC OPTIONS])..."<<endl;
int process_global_flags(arg_list_t &arg_list)
{
arg_list_t::iterator iter, next;
-
+
for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
{
if(*iter == "--")
signal_test();
return SYNFIGTOOL_HELP;
}
-
+
if(*iter == "--guid-test")
{
guid_test();
return SYNFIGTOOL_HELP;
}
-
+
if(*iter == "--help")
{
display_help(1);
synfig::Target::Book::iterator iter=synfig::Target::book().begin();
for(;iter!=synfig::Target::book().end();iter++)
cout<<iter->first<<endl;
-
+
return SYNFIGTOOL_HELP;
}
synfig::LinkableValueNode::Book::iterator iter=synfig::LinkableValueNode::book().begin();
for(;iter!=synfig::LinkableValueNode::book().end();iter++)
cout<<iter->first<<endl;
-
+
return SYNFIGTOOL_HELP;
}
synfig::Importer::Book::iterator iter=synfig::Importer::book().begin();
for(;iter!=synfig::Importer::book().end();iter++)
cout<<iter->first<<endl;
-
+
return SYNFIGTOOL_HELP;
}
if(*iter == "--version")
{
cerr<<PACKAGE<<" "<<VERSION<<endl;
-
+
arg_list.erase(iter);
-
+
return SYNFIGTOOL_HELP;
}
** published by the Free Software Foundation; either version 2 of\n\
** the License, or (at your option) any later version.\n\
**\n\
-** " << endl << endl;
+** " << endl << endl;
arg_list.erase(iter);
-
+
return SYNFIGTOOL_HELP;
}
if(*iter == "-v")
{
verbosity++;
-
+
arg_list.erase(iter);
-
+
continue;
}
continue;
}
}
-
+
return SYNFIGTOOL_OK;
}
int extract_arg_cluster(arg_list_t &arg_list,arg_list_t &cluster)
{
arg_list_t::iterator iter, next;
-
+
for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
{
if(*iter->begin() != '-')
return SYNFIGTOOL_MISSINGARGUMENT;
}
}
-
+
cluster.push_back(*iter);
arg_list.erase(iter);
}
-
+
return SYNFIGTOOL_OK;
}
arg_list.erase(iter);
}
}
-
+
return SYNFIGTOOL_OK;
}
arg_list.erase(iter);
}
}
-
+
return SYNFIGTOOL_OK;
}
{
arg_list_t::iterator iter, next;
type.clear();
-
+
for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
{
if(*iter=="-t")
{
arg_list_t::iterator iter, next;
filename.clear();
-
+
for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
{
if(*iter=="--append")
arg_list_t::iterator iter, next;
int ret=SYNFIGTOOL_FILENOTFOUND;
outfile.clear();
-
+
for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
{
if(*iter=="-o")
{
arg_list_t::iterator iter, next;
//canvasid.clear();
-
+
for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
{
if(*iter=="-c")
int i;
arg_list_t arg_list;
job_list_t job_list;
-
+
progname=argv[0];
Progress p(argv[0]);
-
+
if(!SYNFIG_CHECK_VERSION())
{
cerr<<_("FATAL: Synfig Version Mismatch")<<endl;
for(i=1;i<argc;i++)
arg_list.push_back(argv[i]);
-
+
if((i=process_global_flags(arg_list)))
return i;
VERBOSE_OUT(1)<<_("verbosity set to ")<<verbosity<<endl;
synfig::Main synfig_main(dirname(progname),&p);
-
+
{
arg_list_t defaults, imageargs;
int ret;
-
+
// Grab the defaults before the first file
if ((ret = extract_arg_cluster(arg_list,defaults)) != SYNFIGTOOL_OK)
return ret;
-
+
while(arg_list.size())
{
string target_name;
job_list.push_front(Job());
int threads=0;
-
+
imageargs=defaults;
job_list.front().filename=arg_list.front();
arg_list.pop_front();
if ((ret = extract_arg_cluster(arg_list,imageargs)) != SYNFIGTOOL_OK)
return ret;
-
+
// Open the composition
{
job_list.front().root=open_canvas(job_list.front().filename);
}
job_list.front().root->set_time(0);
-
+
string canvasid;
extract_canvasid(imageargs,canvasid);
if(!canvasid.empty())
cerr<<_("Throwing out job...")<<endl;
job_list.pop_front();
continue;
-
+
}
catch(Exception::BadLinkName)
{
cerr<<_("Throwing out job...")<<endl;
job_list.pop_front();
continue;
-
+
}
}
else
job_list.front().canvas=job_list.front().root;
-
+
extract_RendDesc(imageargs,job_list.front().canvas->rend_desc());
extract_target(imageargs,target_name);
extract_threads(imageargs,threads);
VERBOSE_OUT(2)<<_("Appended contents of ")<<composite_file<<endl;
}
}while(false);
-
+
VERBOSE_OUT(4)<<_("Attempting to determine target/outfile...")<<endl;
-
+
// If the target type is not yet defined,
// try to figure it out from the outfile.
if(target_name.empty() && !job_list.front().outfilename.empty())
VERBOSE_OUT(4)<<"target_name="<<target_name<<endl;
VERBOSE_OUT(4)<<"outfile_name="<<job_list.front().outfilename<<endl;
-
+
VERBOSE_OUT(4)<<_("Creating the target...")<<endl;
job_list.front().target=synfig::Target::create(target_name,job_list.front().outfilename);
-
+
if(target_name=="sif")
{
job_list.front().sifout=true;
{
VERBOSE_OUT(4)<<_("Setting the canvas on the target...")<<endl;
job_list.front().target->set_canvas(job_list.front().canvas);
- VERBOSE_OUT(4)<<_("Setting the quality of the target...")<<endl;
+ VERBOSE_OUT(4)<<_("Setting the quality of the target...")<<endl;
job_list.front().target->set_quality(job_list.front().quality);
}
-
+
// Set the threads for the target
if(job_list.front().target && Target_Scanline::Handle::cast_dynamic(job_list.front().target))
{
Target_Scanline::Handle::cast_dynamic(job_list.front().target)->set_threads(threads);
}
-
+
if(imageargs.size())
{
cerr<<_("Unidentified arguments for ")<<job_list.front().filename<<": ";
//getline(cin,bleh);
}
}
-
+
if(arg_list.size())
{
cerr<<_("Unidentified arguments:");
cerr<<endl;
return SYNFIGTOOL_UNKNOWNARGUMENT;
}
-
+
if(!job_list.size())
{
cerr<<_("Nothing to do!")<<endl;
return SYNFIGTOOL_BORRED;
}
-
+
for(;job_list.size();job_list.pop_front())
{
VERBOSE_OUT(3)<<job_list.front().filename<<" -- "<<endl<<'\t'<<
job_list.front().desc.get_br()[0],job_list.front().desc.get_br()[1],
job_list.front().desc.get_focus()[0],job_list.front().desc.get_focus()[1]
)<<endl;
-
+
RenderProgress p;
p.task(job_list.front().filename+" ==> "+job_list.front().outfilename);
if(!job_list.front().sifout)
}
}
}
-
+
job_list.clear();
-
+
VERBOSE_OUT(1)<<_("Done.")<<endl;
-
+
return SYNFIGTOOL_OK;
}
#define HAVE_LIBDL 1
/* Define if JPEG library is available */
-#define HAVE_LIBJPEG
+#define HAVE_LIBJPEG
/* Define if PNG library is available */
-#define HAVE_LIBPNG
+#define HAVE_LIBPNG
/* Define to 1 if you have the `pthread' library (-lpthread). */
#define HAVE_LIBPTHREAD 1
/* Define if TIFF library is available */
-#define HAVE_LIBTIFF
+#define HAVE_LIBTIFF
/* Define to 1 if you have the <mach-o/dyld.h> header file. */
#define HAVE_MACH_O_DYLD_H 1
#define VERSION "0.61.05-257"
/* enable fontconfig support */
-#define WITH_FONTCONFIG
+#define WITH_FONTCONFIG
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */