1 /* === S Y N F I G ========================================================= */
2 /*! \file layer_bitmap.cpp
3 ** \brief Template Header
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include "layer_bitmap.h"
46 #include "paramdesc.h"
51 /* === U S I N G =========================================================== */
53 using namespace synfig;
57 /* === G L O B A L S ======================================================= */
59 /* === P R O C E D U R E S ================================================= */
61 /* === M E T H O D S ======================================================= */
63 synfig::Layer_Bitmap::Layer_Bitmap():
64 Layer_Composite (1.0,Color::BLEND_COMPOSITE),
72 Layer::Vocab voc(get_param_vocab());
73 Layer::fill_static(voc);
74 set_param_static("c", true);
78 synfig::Layer_Bitmap::set_param(const String & param, ValueBase value)
83 if(param=="gamma_adjust"&& value.get_type()==ValueBase::TYPE_REAL)
85 set_param_static(param, value.get_static());
86 gamma_adjust=1.0/value.get(Real());
87 //gamma_adjust.set_gamma(1.0/value.get(Real()));
91 return Layer_Composite::set_param(param,value);
95 synfig::Layer_Bitmap::get_param(const String & param)const
100 if(param=="gamma_adjust")
102 ValueBase ret(1.0/gamma_adjust);
103 ret.set_static(get_param_static(param));
109 ValueBase ret1(ValueBase::TYPE_INTEGER);
111 ValueBase ret2(surface.get_w());
112 ret1.set_static(get_param_static(param));
113 ret2.set_static(get_param_static(param));
114 if (trimmed) return ret1;
119 ValueBase ret1(ValueBase::TYPE_INTEGER);
121 ValueBase ret2(surface.get_h());
122 ret1.set_static(get_param_static(param));
123 ret2.set_static(get_param_static(param));
124 if (trimmed) return ret1;
128 return Layer_Composite::get_param(param);
132 Layer_Bitmap::get_param_vocab()const
134 Layer::Vocab ret(Layer_Composite::get_param_vocab());
136 ret.push_back(ParamDesc("tl")
137 .set_local_name(_("Top-Left"))
138 .set_description(_("Upper left-hand Corner of image"))
141 ret.push_back(ParamDesc("br")
142 .set_local_name(_("Bottom-Right"))
143 .set_description(_("Lower right-hand Corner of image"))
146 ret.push_back(ParamDesc("c")
147 .set_local_name(_("Interpolation"))
148 .set_description(_("What type of interpolation to use"))
150 .add_enum_value(0,"nearest",_("Nearest Neighbor"))
151 .add_enum_value(1,"linear",_("Linear"))
152 .add_enum_value(2,"cosine",_("Cosine"))
153 .add_enum_value(3,"cubic",_("Cubic"))
156 ret.push_back(ParamDesc("gamma_adjust")
157 .set_local_name(_("Gamma Adjustment"))
163 synfig::Layer::Handle
164 Layer_Bitmap::hit_check(synfig::Context context, const synfig::Point &pos)const
169 surface_pos[0]/=br[0]-tl[0];
170 if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0)
172 surface_pos[1]/=br[1]-tl[1];
173 if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0)
175 return const_cast<Layer_Bitmap*>(this);
179 return context.hit_check(pos);
184 synfig::Layer_Bitmap::filter(Color& x)const
186 if(gamma_adjust!=1.0)
188 x.set_r(powf((float)x.get_r(),gamma_adjust));
189 x.set_g(powf((float)x.get_g(),gamma_adjust));
190 x.set_b(powf((float)x.get_b(),gamma_adjust));
196 synfig::Layer_Bitmap::get_color(Context context, const Point &pos)const
201 return context.get_color(pos);
205 surface_pos[0]/=br[0]-tl[0];
206 if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0)
208 surface_pos[1]/=br[1]-tl[1];
209 if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0)
213 surface_pos[0]*=width;
214 surface_pos[1]*=height;
216 if (surface_pos[0] > left+surface.get_w() || surface_pos[0] < left || surface_pos[1] > top+surface.get_h() || surface_pos[1] < top)
217 return context.get_color(pos);
219 surface_pos[0] -= left;
220 surface_pos[1] -= top;
224 surface_pos[0]*=surface.get_w();
225 surface_pos[1]*=surface.get_h();
228 Color ret(Color::alpha());
236 ret=surface.cubic_sample(surface_pos[0],surface_pos[1]);
240 ret=surface.cosine_sample(surface_pos[0],surface_pos[1]);
243 ret=surface.linear_sample(surface_pos[0],surface_pos[1]);
245 case 0: // Nearest Neighbor
248 int x(min(surface.get_w()-1,max(0,round_to_int(surface_pos[0]))));
249 int y(min(surface.get_h()-1,max(0,round_to_int(surface_pos[1]))));
257 if(get_amount()==1 && get_blend_method()==Color::BLEND_STRAIGHT)
260 return Color::blend(ret,context.get_color(pos),get_amount(),get_blend_method());
264 return context.get_color(pos);
268 Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
273 else if(quality>=5 && interp>1)
276 // We can only handle NN and Linear at the moment
278 // return Layer_Composite::accelerated_render(context,out_surface,quality,renddesc,cb);
280 //if we don't actually have a valid surface just skip us
281 if(!surface.is_valid())
283 // Render what is behind us
284 return context.accelerated_render(out_surface,quality,renddesc,cb);
287 SuperCallback subcb(cb,1,10000,10001+renddesc.get_h());
289 if( get_amount()==1 &&
290 get_blend_method()==Color::BLEND_STRAIGHT &&
292 renddesc.get_tl()==tl &&
293 renddesc.get_br()==br)
295 // Check for the trivial case
296 if(surface.get_w()==renddesc.get_w() && surface.get_h()==renddesc.get_h() && gamma_adjust==1.0f)
298 if(cb && !cb->amount_complete(0,100)) return false;
299 *out_surface=surface;
300 if(cb && !cb->amount_complete(100,100)) return false;
303 out_surface->set_wh(renddesc.get_w(),renddesc.get_h());
307 // Render what is behind us
308 if(!context.accelerated_render(out_surface,quality,renddesc,&subcb))
312 if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
314 Point obr = renddesc.get_br(),
315 otl = renddesc.get_tl();
317 //Vector::value_type pw=renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
318 //Vector::value_type ph=renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
320 //A = representation of input (just tl,br) //just a scaling right now
321 //B = representation of output (just tl,br) //just a scaling right now
322 //sa = scaling for input (0,1) -> (0,w/h)
323 //sb = scaling for output (0,1) -> (0,w/h)
325 float outwf = obr[0] - otl[0];
326 float outhf = obr[1] - otl[1];
328 int inw = surface.get_w();
329 int inh = surface.get_h();
331 int outw = renddesc.get_w();
332 int outh = renddesc.get_h();
339 inwf = (br[0] - tl[0])*surface.get_w()/width;
340 inhf = (br[1] - tl[1])*surface.get_h()/height;
341 itl = Point(tl[0] + (br[0]-tl[0])*left/width,
342 tl[1] + (br[1]-tl[1])*top/height);
343 ibr = Point(tl[0] + (br[0]-tl[0])*(left+inw)/width,
344 tl[1] + (br[1]-tl[1])*(top+inh)/height);
348 inwf = br[0] - tl[0];
349 inhf = br[1] - tl[1];
354 //need to get the input coords in output space, so we can clip
356 //get the desired corners of the bitmap (in increasing order) in integers
357 //floating point corners
358 float x1f = (itl[0] - otl[0])*outw/outwf;
359 float x2f = (ibr[0] - otl[0])*outw/outwf;
360 float y1f = (itl[1] - otl[1])*outh/outhf;
361 float y2f = (ibr[1] - otl[1])*outh/outhf;
363 if(x1f > x2f) swap(x1f,x2f);
364 if(y1f > y2f) swap(y1f,y2f);
366 int x_start = max(0,(int)floor(x1f)); //probably floor
367 int x_end = min(outw,(int)ceil(x2f)); //probably ceil
368 int y_start = max(0,(int)floor(y1f)); //probably floor
369 int y_end = min(outh,(int)ceil(y2f)); //probably ceil
371 //need to get the x,y,dx,dy values from output space to input, so we can do fast interpolation
373 //get the starting position in input space... for interpolating
375 // in int -> out float:
376 // Sb(B^-1)A(Sa^-1) x
377 float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - itl[0])*inw/inwf; //may want to bias this (center of pixel)???
378 float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - itl[1])*inh/inhf; //may want to bias this (center of pixel)???
380 //calculate the delta values in input space for one pixel movement in output space
381 //same matrix but with a vector instead of a point...
382 float indx = outwf*(inw)/((outw)*inwf); //translations died
383 float indy = outhf*(inh)/((outh)*inhf); //translations died
385 //perhaps use a DDA algorithm... if faster...
386 // will still want pixel fractions to be floating point since colors are
388 //synfig::info("xstart:%d ystart:%d xend:%d yend:%d",x_start,y_start,x_end,y_end);
390 //start drawing at the start of the bitmap (either origin or corner of input...)
392 Surface::alpha_pen pen(out_surface->get_pen(x_start,y_start));
393 pen.set_alpha(get_amount());
394 pen.set_blend_method(get_blend_method());
396 //check if we should use the downscale filtering
399 //the stride of the value should be inverted because we want to downsample
400 //when the stride is small, not big
401 //int multw = (int)ceil(indx);
402 //int multh = (int)ceil(indy);
404 if(indx > 1.7 || indy > 1.7)
406 /*synfig::info("Decided to downsample? ratios - (%f,%f) -> (%d,%d)",
407 indx, indy, multw, multh); */
409 //use sample rect here...
414 //Point sample - truncate
415 iny = iny_start;//+0.5f;
416 for(y = y_start; y < y_end; ++y, pen.inc_y(), iny += indy)
418 inx = inx_start;//+0.5f;
419 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
421 Color rc = surface.sample_rect_clip(inx,iny,inx+indx,iny+indy);
422 pen.put_value(filter(rc));
424 pen.dec_x(x_end-x_start);
427 //Color c = (*out_surface)[0][0];
428 //synfig::info("ValueBase of first pixel = (%f,%f,%f,%f)",c.get_r(),c.get_g(),c.get_b(),c.get_a());
434 //perform normal interpolation
437 //synfig::info("Decided to do nearest neighbor");
441 //Point sample - truncate
442 iny = iny_start;//+0.5f;
443 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
445 inx = inx_start;//+0.5f;
446 int yclamp = min(inh-1, max(0, round_to_int(iny)));
447 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
449 int xclamp = min(inw-1, max(0, round_to_int(inx)));
450 Color c = filter(surface[yclamp][xclamp]);
451 pen.put_value(c); //must get rid of the clip
453 pen.dec_x(x_end-x_start);
461 //float xmf,xpf,ymf,ypf;
466 //can probably buffer for x values...
468 //loop and based on inx,iny sample input image
470 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
473 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
475 Color col(surface.linear_sample(inx,iny));
476 pen.put_value(filter(col));
478 pen.dec_x(x_end-x_start);
487 //float xmf,xpf,ymf,ypf;
492 //can probably buffer for x values...
494 //loop and based on inx,iny sample input image
496 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
499 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
501 Color col(surface.cosine_sample(inx,iny));
502 pen.put_value(filter(col));
504 pen.dec_x(x_end-x_start);
512 //float xmf,xpf,ymf,ypf;
517 //can probably buffer for x values...
519 //loop and based on inx,iny sample input image
521 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
524 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
526 Color col(surface.cubic_sample(inx,iny));
527 pen.put_value(filter(col));
529 pen.dec_x(x_end-x_start);
538 Layer_Bitmap::get_bounding_rect()const