/* === S Y N F I G ========================================================= */
/*! \file sphere_distort.cpp
-** \brief Sphere Distort File
+** \brief Implementation of the "Spherize" layer
**
-** $Id: sphere_distort.cpp,v 1.2 2005/01/24 05:00:18 darco Exp $
+** $Id$
**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** Copyright (c) 2007, 2008 Chris Moore
**
** This package is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License as
SYNFIG_LAYER_INIT(Layer_SphereDistort);
SYNFIG_LAYER_SET_NAME(Layer_SphereDistort,"spherize");
-SYNFIG_LAYER_SET_LOCAL_NAME(Layer_SphereDistort,_("Spherize"));
-SYNFIG_LAYER_SET_CATEGORY(Layer_SphereDistort,_("Distortions"));
+SYNFIG_LAYER_SET_LOCAL_NAME(Layer_SphereDistort,N_("Spherize"));
+SYNFIG_LAYER_SET_CATEGORY(Layer_SphereDistort,N_("Distortions"));
SYNFIG_LAYER_SET_VERSION(Layer_SphereDistort,"0.2");
-SYNFIG_LAYER_SET_CVS_ID(Layer_SphereDistort,"$Id: sphere_distort.cpp,v 1.2 2005/01/24 05:00:18 darco Exp $");
+SYNFIG_LAYER_SET_CVS_ID(Layer_SphereDistort,"$Id$");
/* === P R O C E D U R E S ================================================= */
/* === E N T R Y P O I N T ================================================= */
Layer_SphereDistort::Layer_SphereDistort()
-:Layer_Composite(1.0,Color::BLEND_STRAIGHT),
-center(0,0),
+:center(0,0),
radius(1),
percent(1.0),
type(TYPE_NORMAL),
{
}
-
+
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)) ||
(type == TYPE_DISTV && (sphr.miny >= windr.maxy || windr.miny >= sphr.maxy)) )
{
//synfig::warning("Spherize: Bounding box reject");
- return context.accelerated_render(surface,quality,renddesc,cb);
+ if (clip)
+ {
+ surface->set_wh(renddesc.get_w(), renddesc.get_h());
+ surface->clear();
+ return true;
+ }
+ else
+ 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
+
+ //now get transforms and expand the rectangle to accommodate
Point p = sphtrans(close,center,radius,percent,type);
expandr.expand(p[0],p[1]);
p = sphtrans(origin[i],center,radius,percent,type);
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...)
+
+ //now that we have the bounding 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
- if(quality <= 4) //cubic
- {
+
+ //sample at that pixel location based on the quality
+ if(quality <= 4) // cubic
p.put_value(background.cubic_sample(xs,ys));
- }else if(quality <= 5) //cosine
- {
+ else if(quality <= 5) // cosine
p.put_value(background.cosine_sample(xs,ys));
- }else if(quality <= 6) //linear
- {
+ else if(quality <= 6) // linear
p.put_value(background.linear_sample(xs,ys));
- }else //nearest
- {
+ else // nearest
p.put_value(background[round_to_int(ys)][round_to_int(xs)]);
- }
}
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);
Layer_SphereDistort::get_bounding_rect()const
{
Rect bounds(Rect::full_plane());
+
+ if (clip)
+ return bounds;
+
switch(type)
{
case TYPE_NORMAL:
- bounds=Rect(
- center[0]+(radius),
- center[1]+(radius),
- center[0]-(radius),
- center[1]-(radius)
- );
+ bounds=Rect(center[0]+radius, center[1]+radius,
+ center[0]-radius, center[1]-radius);
break;
case TYPE_DISTH:
+ bounds = Rect::vertical_strip(center[0]-radius, center[0]+radius);
break;
case TYPE_DISTV:
+ bounds = Rect::horizontal_strip(center[1]-radius, center[1]+radius);
break;
default:
break;
}
-
+
return bounds;
}
-