/*! \file layer_bitmap.cpp
** \brief Template Header
**
-** $Id: layer_bitmap.cpp,v 1.2 2005/01/24 03:08:18 darco Exp $
+** $Id$
**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
br (0.5,-0.5),
c (1),
surface (128,128),
+ trimmed (false),
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);
}
if(param=="_width")
{
+ if (trimmed) return int(width);
return surface.get_w();
}
if(param=="_height")
{
+ if (trimmed) return int(height);
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[1]/=br[1]-tl[1];
if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0)
{
- surface_pos[0]*=surface.get_w();
- surface_pos[1]*=surface.get_h();
-
+ if (trimmed)
+ {
+ surface_pos[0]*=width;
+ surface_pos[1]*=height;
+
+ if (surface_pos[0] > left+surface.get_w() || surface_pos[0] < left || surface_pos[1] > top+surface.get_h() || surface_pos[1] < top)
+ return context.get_color(pos);
+
+ surface_pos[0] -= left;
+ surface_pos[1] -= top;
+ }
+ else
+ {
+ 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 &&
get_blend_method()==Color::BLEND_STRAIGHT &&
+ !trimmed &&
renddesc.get_tl()==tl &&
renddesc.get_br()==br)
{
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();
-
+
+ float inwf, inhf;
+ Point itl, ibr;
+
+ if (trimmed)
+ {
+ inwf = (br[0] - tl[0])*surface.get_w()/width;
+ inhf = (br[1] - tl[1])*surface.get_h()/height;
+ itl = Point(tl[0] + (br[0]-tl[0])*left/width,
+ tl[1] + (br[1]-tl[1])*top/height);
+ ibr = Point(tl[0] + (br[0]-tl[0])*(left+inw)/width,
+ tl[1] + (br[1]-tl[1])*(top+inh)/height);
+ }
+ else
+ {
+ inwf = br[0] - tl[0];
+ inhf = br[1] - tl[1];
+ itl = tl;
+ ibr = br;
+ }
+
//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;
-
+ float x1f = (itl[0] - otl[0])*outw/outwf;
+ float x2f = (ibr[0] - otl[0])*outw/outwf;
+ float y1f = (itl[1] - otl[1])*outh/outhf;
+ float y2f = (ibr[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)???
-
+ float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - itl[0])*inw/inwf; //may want to bias this (center of pixel)???
+ float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - itl[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;
}