1 /* === S I N F G =========================================================== */
2 /*! \file layer_bitmap.cpp
3 ** \brief Template Header
5 ** $Id: layer_bitmap.cpp,v 1.2 2005/01/24 03:08:18 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
24 #define SINFG_NO_ANGLE
33 #include "layer_bitmap.h"
47 #include "paramdesc.h"
52 /* === U S I N G =========================================================== */
54 using namespace sinfg;
58 /* === G L O B A L S ======================================================= */
60 /* === P R O C E D U R E S ================================================= */
62 /* === M E T H O D S ======================================================= */
64 sinfg::Layer_Bitmap::Layer_Bitmap():
65 Layer_Composite (1.0,Color::BLEND_COMPOSITE),
75 sinfg::Layer_Bitmap::set_param(const String & param, ValueBase value)
80 if(param=="gamma_adjust"&& value.get_type()==ValueBase::TYPE_REAL)
82 gamma_adjust=1.0/value.get(Real());
83 //gamma_adjust.set_gamma(1.0/value.get(Real()));
87 return Layer_Composite::set_param(param,value);
91 sinfg::Layer_Bitmap::get_param(const String & param)const
96 if(param=="gamma_adjust")
97 return 1.0/gamma_adjust;
101 return surface.get_w();
105 return surface.get_h();
108 return Layer_Composite::get_param(param);
112 Layer_Bitmap::get_param_vocab()const
114 Layer::Vocab ret(Layer_Composite::get_param_vocab());
116 ret.push_back(ParamDesc("tl")
117 .set_local_name(_("Top-Left"))
118 .set_description(_("Upper left-hand Corner of image"))
121 ret.push_back(ParamDesc("br")
122 .set_local_name(_("Bottom-Right"))
123 .set_description(_("Lower right-hand Corner of image"))
126 ret.push_back(ParamDesc("c")
127 .set_local_name(_("Interpolation"))
128 .set_description(_("What type of interpolation to use"))
130 .add_enum_value(0,"nearest",_("Nearest Neighbor"))
131 .add_enum_value(1,"linear",_("Linear"))
132 .add_enum_value(2,"cosine",_("Cosine"))
133 .add_enum_value(3,"cubic",_("Cubic"))
136 ret.push_back(ParamDesc("gamma_adjust")
137 .set_local_name(_("Gamma Adjustment"))
144 Layer_Bitmap::hit_check(sinfg::Context context, const sinfg::Point &pos)const
149 surface_pos[0]/=br[0]-tl[0];
150 if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0)
152 surface_pos[1]/=br[1]-tl[1];
153 if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0)
155 return const_cast<Layer_Bitmap*>(this);
159 return context.hit_check(pos);
164 sinfg::Layer_Bitmap::filter(const Color& c)const
166 if(gamma_adjust==1.0)
171 x.set_r(powf((float)x.get_r(),gamma_adjust));
172 x.set_g(powf((float)x.get_g(),gamma_adjust));
173 x.set_b(powf((float)x.get_b(),gamma_adjust));
178 sinfg::Layer_Bitmap::get_color(Context context, const Point &pos)const
183 return context.get_color(pos);
187 surface_pos[0]/=br[0]-tl[0];
188 if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0)
190 surface_pos[1]/=br[1]-tl[1];
191 if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0)
193 surface_pos[0]*=surface.get_w();
194 surface_pos[1]*=surface.get_h();
196 Color ret(Color::alpha());
204 ret=surface.cubic_sample(surface_pos[0],surface_pos[1]);
208 ret=surface.cosine_sample(surface_pos[0],surface_pos[1]);
211 ret=surface.linear_sample(surface_pos[0],surface_pos[1]);
213 case 0: // Nearest Neighbor
216 int x(min(surface.get_w()-1,max(0,round_to_int(surface_pos[0]))));
217 int y(min(surface.get_h()-1,max(0,round_to_int(surface_pos[1]))));
225 if(get_amount()==1 && get_blend_method()==Color::BLEND_STRAIGHT)
228 return Color::blend(ret,context.get_color(pos),get_amount(),get_blend_method());
232 return context.get_color(pos);
236 Layer_Bitmap::accelerated_render(Context context,Surface *out_surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
241 else if(quality>=5 && interp>1)
244 // We can only handle NN and Linear at the moment
246 // return Layer_Composite::accelerated_render(context,out_surface,quality,renddesc,cb);
248 //if we don't actually have a valid surface just skip us
249 if(!surface.is_valid())
251 // Render what is behind us
252 return context.accelerated_render(out_surface,quality,renddesc,cb);
255 SuperCallback subcb(cb,1,10000,10001+renddesc.get_h());
257 if( get_amount()==1 &&
258 get_blend_method()==Color::BLEND_STRAIGHT &&
259 renddesc.get_tl()==tl &&
260 renddesc.get_br()==br)
262 // Check for the trivial case
263 if(surface.get_w()==renddesc.get_w() && surface.get_h()==renddesc.get_h() && gamma_adjust==1.0f)
265 if(cb && !cb->amount_complete(0,100)) return false;
266 *out_surface=surface;
267 if(cb && !cb->amount_complete(100,100)) return false;
270 out_surface->set_wh(renddesc.get_w(),renddesc.get_h());
274 // Render what is behind us
275 if(!context.accelerated_render(out_surface,quality,renddesc,&subcb))
279 if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false;
281 Point obr = renddesc.get_br(),
282 otl = renddesc.get_tl();
284 //Vector::value_type pw=renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
285 //Vector::value_type ph=renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
287 //A = representation of input (just tl,br) //just a scaling right now
288 //B = representation of output (just tl,br) //just a scaling right now
289 //sa = scaling for input (0,1) -> (0,w/h)
290 //sb = scaling for output (0,1) -> (0,w/h)
292 float inwf = br[0] - tl[0];
293 float inhf = br[1] - tl[1];
295 float outwf = obr[0] - otl[0];
296 float outhf = obr[1] - otl[1];
298 int inw = surface.get_w();
299 int inh = surface.get_h();
301 int outw = renddesc.get_w();
302 int outh = renddesc.get_h();
304 //need to get the input coords in output space, so we can clip
306 //get the desired corners of the bitmap (in increasing order) in integers
307 //floating point corners
308 float x1f = (tl[0] - otl[0])*outw/outwf;
309 float x2f = (br[0] - otl[0])*outw/outwf;
310 float y1f = (tl[1] - otl[1])*outh/outhf;
311 float y2f = (br[1] - otl[1])*outh/outhf;
313 if(x1f > x2f) swap(x1f,x2f);
314 if(y1f > y2f) swap(y1f,y2f);
316 int x_start = max(0,(int)floor(x1f)); //probably floor
317 int x_end = min(outw,(int)ceil(x2f)); //probably ceil
318 int y_start = max(0,(int)floor(y1f)); //probably floor
319 int y_end = min(outh,(int)ceil(y2f)); //probably ceil
321 //need to get the x,y,dx,dy values from output space to input, so we can do fast interpolation
323 //get the starting position in input space... for interpolating
325 // in int -> out float:
326 // Sb(B^-1)A(Sa^-1) x
327 float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - tl[0])*inw/inwf; //may want to bias this (center of pixel)???
328 float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - tl[1])*inh/inhf; //may want to bias this (center of pixel)???
330 //calculate the delta values in input space for one pixel movement in output space
331 //same matrix but with a vector instead of a point...
332 float indx = outwf*(inw)/((outw)*inwf); //translations died
333 float indy = outhf*(inh)/((outh)*inhf); //translations died
335 //perhaps use a DDA algorithm... if faster...
336 // will still want pixel fractions to be floating point since colors are
338 //sinfg::info("xstart:%d ystart:%d xend:%d yend:%d",x_start,y_start,x_end,y_end);
340 //start drawing at the start of the bitmap (either origin or corner of input...)
342 Surface::alpha_pen pen(out_surface->get_pen(x_start,y_start));
343 pen.set_alpha(get_amount());
344 pen.set_blend_method(get_blend_method());
346 //check if we should use the downscale filtering
349 //the stride of the value should be inverted because we want to downsample
350 //when the stride is small, not big
351 //int multw = (int)ceil(indx);
352 //int multh = (int)ceil(indy);
354 if(indx > 1.7 || indy > 1.7)
356 /*sinfg::info("Decided to downsample? ratios - (%f,%f) -> (%d,%d)",
357 indx, indy, multw, multh); */
359 //use sample rect here...
364 //Point sample - truncate
365 iny = iny_start;//+0.5f;
366 for(y = y_start; y < y_end; ++y, pen.inc_y(), iny += indy)
368 inx = inx_start;//+0.5f;
369 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
371 Color rc = surface.sample_rect_clip(inx,iny,inx+indx,iny+indy);
372 pen.put_value(filter(rc));
374 pen.dec_x(x_end-x_start);
377 //Color c = (*out_surface)[0][0];
378 //sinfg::info("ValueBase of first pixel = (%f,%f,%f,%f)",c.get_r(),c.get_g(),c.get_b(),c.get_a());
384 //perform normal interpolation
387 //sinfg::info("Decided to do nearest neighbor");
391 //Point sample - truncate
392 iny = iny_start;//+0.5f;
393 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
395 inx = inx_start;//+0.5f;
396 int yclamp = min(inh-1, max(0, round_to_int(iny)));
397 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
399 int xclamp = min(inw-1, max(0, round_to_int(inx)));
400 Color c = filter(surface[yclamp][xclamp]);
401 pen.put_value(c); //must get rid of the clip
403 pen.dec_x(x_end-x_start);
411 //float xmf,xpf,ymf,ypf;
416 //can probably buffer for x values...
418 //loop and based on inx,iny sample input image
420 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
423 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
425 pen.put_value(filter(surface.linear_sample(inx,iny)));
427 pen.dec_x(x_end-x_start);
436 //float xmf,xpf,ymf,ypf;
441 //can probably buffer for x values...
443 //loop and based on inx,iny sample input image
445 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
448 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
450 pen.put_value(filter(surface.cosine_sample(inx,iny)));
452 pen.dec_x(x_end-x_start);
460 //float xmf,xpf,ymf,ypf;
465 //can probably buffer for x values...
467 //loop and based on inx,iny sample input image
469 for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy)
472 for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx)
474 pen.put_value(filter(surface.cubic_sample(inx,iny)));
476 pen.dec_x(x_end-x_start);
485 Layer_Bitmap::get_bounding_rect()const