Remove .gitignore do nothing is ignored.
[synfig.git] / synfig-core / trunk / src / synfig / layer_bitmap.cpp
index 27d3911..cda5d09 100644 (file)
@@ -2,7 +2,7 @@
 /*!    \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
@@ -68,10 +68,11 @@ synfig::Layer_Bitmap::Layer_Bitmap():
        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)
 {
@@ -84,7 +85,7 @@ 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);
 }
 
@@ -99,13 +100,15 @@ synfig::Layer_Bitmap::get_param(const String & param)const
 
        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);
 }
 
@@ -113,7 +116,7 @@ Layer::Vocab
 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"))
@@ -146,7 +149,7 @@ Layer_Bitmap::hit_check(synfig::Context context, const synfig::Point &pos)const
 {
        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)
        {
@@ -156,22 +159,20 @@ Layer_Bitmap::hit_check(synfig::Context context, const synfig::Point &pos)const
                        return const_cast<Layer_Bitmap*>(this);
                }
        }
-       
+
        return context.hit_check(pos);
 }
 
 inline
 const Color&
-synfig::Layer_Bitmap::filter(const Color& c)const
+synfig::Layer_Bitmap::filter(Color& x)const
 {
-       if(gamma_adjust==1.0)
-               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(gamma_adjust!=1.0)
+       {
+               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));
+       }
        return x;
 }
 
@@ -182,18 +183,32 @@ synfig::Layer_Bitmap::get_color(Context context, const Point &pos)const
 
        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)
@@ -220,16 +235,16 @@ synfig::Layer_Bitmap::get_color(Context context, const Point &pos)const
                                }
                        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);
 }
 
@@ -245,18 +260,19 @@ Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int qualit
        // 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)
        {
@@ -276,92 +292,109 @@ Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int qualit
                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)
@@ -374,21 +407,21 @@ Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int qualit
                                }
                                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)
@@ -408,14 +441,14 @@ Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int qualit
        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)
@@ -423,24 +456,25 @@ Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int qualit
                        inx = inx_start;
                        for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
                        {
-                               pen.put_value(filter(surface.linear_sample(inx,iny)));
+                               Color col(surface.linear_sample(inx,iny));
+                               pen.put_value(filter(col));
                        }
                        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)
@@ -448,23 +482,24 @@ Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int qualit
                        inx = inx_start;
                        for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
                        {
-                               pen.put_value(filter(surface.cosine_sample(inx,iny)));
+                               Color col(surface.cosine_sample(inx,iny));
+                               pen.put_value(filter(col));
                        }
                        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)
@@ -472,12 +507,13 @@ Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int qualit
                        inx = inx_start;
                        for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
                        {
-                               pen.put_value(filter(surface.cubic_sample(inx,iny)));
+                               Color col(surface.cubic_sample(inx,iny));
+                               pen.put_value(filter(col));
                        }
                        pen.dec_x(x_end-x_start);
-                       
+
                }
-       }       
+       }
 
        return true;
 }