ETL  0.04.19
_surface.h
Go to the documentation of this file.
1 
26 /* === S T A R T =========================================================== */
27 
28 #ifndef __ETL__SURFACE_H
29 #define __ETL__SURFACE_H
30 
31 /* === H E A D E R S ======================================================= */
32 
33 #include "_pen.h"
34 #include "_misc.h"
35 #include <algorithm>
36 #include <cstring>
37 
38 /* === M A C R O S ========================================================= */
39 
40 /* === C L A S S E S & S T R U C T S ======================================= */
41 
43 
44 template <typename T, typename AT>
46 {
47 public:
48  typedef T value_type;
49  typedef AT accumulator_type;
50 
51  accumulator_type cook(const value_type& x)const { return (accumulator_type)x; }
52  value_type uncook(const accumulator_type& x)const { return (value_type)x; }
53 };
54 
55 template <typename T, typename AT=T, class VP=value_prep<T,AT> >
56 class surface
57 {
58 public:
59  typedef T value_type;
60  typedef AT accumulator_type;
61  typedef value_type* pointer;
63  typedef const value_type* const_pointer;
68  typedef VP value_prep_type;
69 
72 
73  typedef typename pen::difference_type size_type;
75 
76  typedef typename pen::iterator_x iterator_x;
77  typedef typename pen::iterator_y iterator_y;
80 
81 private:
85  int w_, h_;
86  bool deletable_;
87 
89 
90  void swap(const surface &x)
91  {
95  std::swap(w_,x.w_);
96  std::swap(h_,x.h_);
98  }
99 
100 public:
102  data_(0),
103  zero_pos_(data_),
104  pitch_(0),
105  w_(0),h_(0),
106  deletable_(false) { }
107 
108  surface(value_type* data, int w, int h, bool deletable=false):
109  data_(data),
110  zero_pos_(data),
111  pitch_(sizeof(value_type)*w),
112  w_(w),h_(h),
113  deletable_(deletable) { }
114 
115  surface(value_type* data, int w, int h, typename difference_type::value_type pitch, bool deletable=false):
116  data_(data),
117  zero_pos_(data),
118  pitch_(pitch),
119  w_(w),h_(h),
120  deletable_(deletable) { }
121 
122  surface(const typename size_type::value_type &w, const typename size_type::value_type &h):
123  data_(new value_type[w*h]),
124  zero_pos_(data_),
125  pitch_(sizeof(value_type)*w),
126  w_(w),h_(h),
127  deletable_(true) { }
128 
129  surface(const size_type &s):
130  data_(new value_type[s.x*s.y]),
131  zero_pos_(data_),
132  pitch_(sizeof(value_type)*s.x),
133  w_(s.x),h_(s.y),
134  deletable_(true) { }
135 
136  template <typename _pen>
137  surface(const _pen &_begin, const _pen &_end)
138  {
139  typename _pen::difference_type size=_end-_begin;
140 
141  data_=new value_type[size.x*size.y];
142  w_=size.x;
143  h_=size.y;
145  pitch_=sizeof(value_type)*w_;
146  deletable_=true;
147 
148  int x,y;
149 
150  for(y=0;y<h_;y++)
151  for(x=0;x<w_;x++)
152  (*this)[y][x]=_begin.get_value_at(x,y);
153  }
154 
155  surface(const surface &s):
156  data_(s.data_?(pointer)(new char[s.pitch_*s.h_]):0),
158  pitch_(s.pitch_),
159  w_(s.w_),
160  h_(s.h_),
161  deletable_(s.data_?true:false)
162  {
163  assert(&s);
164  if(s.data_)
165  {
166  assert(data_);
167  memcpy(data_,s.data_,abs(pitch_)*h_);
168  }
169  }
170 
171 public:
173  {
174  if(deletable_)
175  delete [] data_;
176  }
177 
178  size_type
179  size()const
180  { return size_type(w_,h_); }
181 
182  typename size_type::value_type get_pitch()const { return pitch_; }
183  typename size_type::value_type get_w()const { return w_; }
184  typename size_type::value_type get_h()const { return h_; }
185 
186  const surface &mirror(const surface &rhs)
187  {
188  if(deletable_)delete [] data_;
189 
190  data_=rhs.data_;
191  zero_pos_=rhs.zero_pos_;
192  pitch_=rhs.pitch_;
193  w_=rhs.w_;
194  h_=rhs.h_;
195  deletable_=false;
196 
197  return *this;
198  }
199 
200  const surface &operator=(const surface &rhs)
201  {
202  set_wh(rhs.w_,rhs.h_);
203  zero_pos_=data_+(rhs.zero_pos_-rhs.data_);
204  pitch_=rhs.pitch_;
205  deletable_=true;
206 
207  memcpy(data_,rhs.data_,pitch_*h_);
208 
209  return *this;
210  }
211 
212  void
213  copy(const surface &rhs)
214  {
215  if(pitch_!=rhs.pitch_ || w_!=rhs.w_ || h_!=rhs.h_)
216  return;
217  memcpy(data_, rhs.data_, pitch_*h_);
218  }
219 
220  void
221  set_wh(typename size_type::value_type w, typename size_type::value_type h, const typename size_type::value_type &pitch=0)
222  {
223  if(data_)
224  {
225  if(w==w_ && h==h_ && deletable_)
226  return;
227  if(deletable_)
228  delete [] data_;
229  }
230 
231  w_=w;
232  h_=h;
233  if(pitch)
234  pitch_=pitch;
235  else
236  pitch_=sizeof(value_type)*w_;
237  zero_pos_=data_=(pointer)(new char[pitch_*h_]);
238  deletable_=true;
239  }
240 
241  void
242  set_wh(typename size_type::value_type w, typename size_type::value_type h, unsigned char* newdata, const typename size_type::value_type &pitch)
243  {
244  if(data_ && deletable_)
245  {
246  delete [] data_;
247  }
248  w_=w;
249  h_=h;
250  zero_pos_=data_=(pointer)newdata;
251  pitch_=pitch;
252  deletable_=false;
253  }
254 
255  void
256  fill(value_type v, int x, int y, int w, int h)
257  {
258  assert(data_);
259  if(w<=0 || h<=0)return;
260  int i;
261  pen PEN(get_pen(x,y));
262  PEN.set_value(v);
263  for(i=0;i<h;i++,PEN.inc_y(),PEN.dec_x(w))
264  PEN.put_hline(w);
265  }
266 
267  template <class _pen> void
268  fill(value_type v, _pen& PEN, int w, int h)
269  {
270  assert(data_);
271  if(w<=0 || h<=0)return;
272  int y;
273  PEN.set_value(v);
274  for(y=0;y<h;y++,PEN.inc_y(),PEN.dec_x(w))
275  PEN.put_hline(w);
276  }
277 
278  void
280  {
281  assert(data_);
282  int y;
283  pen pen_=begin();
284  pen_.set_value(v);
285  for(y=0;y<h_;y++,pen_.inc_y(),pen_.dec_x(w_))
286  pen_.put_hline(w_);
287  }
288 
289  template <class _pen> void blit_to(_pen &pen)
290  { return blit_to(pen,0,0, get_w(),get_h()); }
291 
292  template <class _pen> void
293  blit_to(_pen &DEST_PEN,
294  int x, int y, int w, int h) //src param
295  {
296  if(x>=w_ || y>=h_)
297  return;
298 
299  //clip source origin
300  if(x<0)
301  {
302  w+=x; //decrease
303  x=0;
304  }
305 
306  if(y<0)
307  {
308  h+=y; //decrease
309  y=0;
310  }
311 
312  //clip width against dest width
313  w = std::min((long)w,(long)(DEST_PEN.end_x()-DEST_PEN.x()));
314  h = std::min((long)h,(long)(DEST_PEN.end_y()-DEST_PEN.y()));
315 
316  //clip width against src width
317  w = std::min(w,w_-x);
318  h = std::min(h,h_-y);
319 
320  if(w<=0 || h<=0)
321  return;
322 
323  pen SOURCE_PEN(get_pen(x,y));
324 
325  for(; h>0; h--,DEST_PEN.inc_y(),SOURCE_PEN.inc_y())
326  {
327  int i;
328  for(i=0; i<w; i++,DEST_PEN.inc_x(),SOURCE_PEN.inc_x())
329  {
330  DEST_PEN.put_value(SOURCE_PEN.get_value());
331  }
332  DEST_PEN.dec_x(w);
333  SOURCE_PEN.dec_x(w);
334  }
335  }
336 
337  void
339  {
340  assert(data_);
341  if(pitch_==(signed int)sizeof(value_type)*w_)
342  memset(data_,0,h_*pitch_);
343  else
344  fill(value_type());
345  }
346 
347  iterator_x
348  operator[](const int &y)
349  { assert(data_); return (pointer)(((char*)zero_pos_)+y*pitch_); }
350 
352  operator[](const int &y)const
353  { assert(data_); return (const_pointer)(((const char*)zero_pos_)+y*pitch_); }
354 
355  void
357  {
358  assert(data_);
359 
360  zero_pos_=(pointer)(((char*)zero_pos_)+pitch_*h_);
361 
362  pitch_=-pitch_;
363  }
364 
365  bool is_valid()const
366  {
367  return data_!=0
368  && zero_pos_!=0
369  && w_>0
370  && h_>0
371  && pitch_!=0
372  ;
373  }
374 
375  operator bool()const { return is_valid(); }
376 
377  pen begin() { assert(data_); return pen(data_,w_,h_,pitch_); }
378  pen get_pen(int x, int y) { assert(data_); return begin().move(x,y); }
379  pen end() { assert(data_); return get_pen(w_,h_); }
380 
381  const_pen begin()const { assert(data_); return const_pen(data_,w_,h_,pitch_); }
382  const_pen get_pen(int x, int y)const { assert(data_); return begin().move(x,y); }
383  const_pen end()const { assert(data_); return get_pen(w_,h_); }
384 
386  value_type linear_sample(const float x, const float y)const
387  {
388  int u(floor_to_int(x)), v(floor_to_int(y));
389  float a, b;
390  static const float epsilon(1.0e-6);
391 
392  if(x<0.0f)u=0,a=0.0f;
393  else if(x>w_-1)u=w_-1,a=0.0f;
394  else a=x-u;
395 
396  if(y<0.0f)v=0,b=0.0f;
397  else if(y>h_-1)v=h_-1,b=0.0f;
398  else b=y-v;
399 
400  const float
401  c(1.0f-a), d(1.0f-b),
402  e(a*d),f(c*b),g(a*b);
403 
404  accumulator_type ret(cooker_.cook((*this)[v][u])*(c*d));
405  if(e>=epsilon)ret+=cooker_.cook((*this)[v][u+1])*e;
406  if(f>=epsilon)ret+=cooker_.cook((*this)[v+1][u])*f;
407  if(g>=epsilon)ret+=cooker_.cook((*this)[v+1][u+1])*g;
408  return cooker_.uncook(ret);
409  }
410 
412  value_type linear_sample_cooked(const float x, const float y)const
413  {
414 #define h(j,i) (((accumulator_type)((*this)[j][i])))
415  int u(floor_to_int(x)), v(floor_to_int(y));
416  float a, b;
417  static const float epsilon(1.0e-6);
418 
419  if(x<0.0f)u=0,a=0.0f;
420  else if(x>w_-1)u=w_-1,a=0.0f;
421  else a=x-u;
422 
423  if(y<0.0f)v=0,b=0.0f;
424  else if(y>h_-1)v=h_-1,b=0.0f;
425  else b=y-v;
426 
427  const float
428  c(1.0f-a), d(1.0f-b),
429  e(a*d),f(c*b),g(a*b);
430 
431  accumulator_type ret(h(v,u)*(c*d));
432  if(e>=epsilon)ret+=h(v,u+1)*e;
433  if(f>=epsilon)ret+=h(v+1,u)*f;
434  if(g>=epsilon)ret+=h(v+1,u+1)*g;
435 
436  return (value_type)(ret);
437 #undef h
438  }
439 
441  value_type cosine_sample(const float x, const float y)const
442  {
443  int u(floor_to_int(x)), v(floor_to_int(y));
444  float a, b;
445  static const float epsilon(1.0e-6);
446 
447  if(x<0.0f)u=0,a=0.0f;
448  else if(x>w_-1)u=w_-1,a=0.0f;
449  else a=x-u;
450 
451  if(y<0.0f)v=0,b=0.0f;
452  else if(y>h_-1)v=h_-1,b=0.0f;
453  else b=y-v;
454 
455  a=(1.0f-cos(a*3.1415927f))*0.5f;
456  b=(1.0f-cos(b*3.1415927f))*0.5f;
457 
458  const float
459  c(1.0f-a), d(1.0f-b),
460  e(a*d),f(c*b),g(a*b);
461 
462  accumulator_type ret(cooker_.cook((*this)[v][u])*(c*d));
463  if(e>=epsilon)ret+=cooker_.cook((*this)[v][u+1])*e;
464  if(f>=epsilon)ret+=cooker_.cook((*this)[v+1][u])*f;
465  if(g>=epsilon)ret+=cooker_.cook((*this)[v+1][u+1])*g;
466 
467  return cooker_.uncook(ret);
468  }
469 
471  value_type cosine_sample_cooked(const float x, const float y)const
472  {
473 #define h(j,i) (((accumulator_type)((*this)[j][i])))
474 
475  int u(floor_to_int(x)), v(floor_to_int(y));
476  float a, b;
477  static const float epsilon(1.0e-6);
478 
479  if(x<0.0f)u=0,a=0.0f;
480  else if(x>w_-1)u=w_-1,a=0.0f;
481  else a=x-u;
482 
483  if(y<0.0f)v=0,b=0.0f;
484  else if(y>h_-1)v=h_-1,b=0.0f;
485  else b=y-v;
486 
487  a=(1.0f-cos(a*3.1415927f))*0.5f;
488  b=(1.0f-cos(b*3.1415927f))*0.5f;
489 
490  const float
491  c(1.0f-a), d(1.0f-b),
492  e(a*d),f(c*b),g(a*b);
493 
494  accumulator_type ret(h(v,u)*(c*d));
495  if(e>=epsilon)ret+=h(v,u+1)*e;
496  if(f>=epsilon)ret+=h(v+1,u)*f;
497  if(g>=epsilon)ret+=h(v+1,u+1)*g;
498 
499  return (value_type)(ret);
500 #undef h
501  }
502 
504  value_type cubic_sample(float x, float y)const
505  {
506  #if 0
507  #define P(x) (((x)>=0)?((x)*(x)*(x)):0.0f)
508  #define R(x) ( P(x+2) - 4.0f*P(x+1) + 6.0f*P(x) - 4.0f*P(x-1) )*(1.0f/6.0f)
509  #define F(i,j) (cooker_.cook((*this)[max(min(j+v,h_-1),0)][max(min(i+u,w_-1),0)])*(R((i)-a)*R(b-(j))))
510  #define Z(i,j) ret+=F(i,j)
511  #define X(i,j) // placeholder... To make box more symmetric
512 
513  int u(floor_to_int(x)), v(floor_to_int(y));
514  float a, b;
515 
516  // Clamp X
517  if(x<0.0f)u=0,a=0.0f;
518  else if(u>w_-1)u=w_-1,a=0.0f;
519  else a=x-u;
520 
521  // Clamp Y
522  if(y<0.0f)v=0,b=0.0f;
523  else if(v>h_-1)v=h_-1,b=0.0f;
524  else b=y-v;
525 
526  // Interpolate
527  accumulator_type ret(F(0,0));
528  Z(-1,-1); Z(-1, 0); Z(-1, 1); Z(-1, 2);
529  Z( 0,-1); X( 0, 0); Z( 0, 1); Z( 0, 2);
530  Z( 1,-1); Z( 1, 0); Z( 1, 1); Z( 1, 2);
531  Z( 2,-1); Z( 2, 0); Z( 2, 1); Z( 2, 2);
532 
533  return cooker_.uncook(ret);
534 
535  #undef X
536  #undef Z
537  #undef F
538  #undef P
539  #undef R
540  #else
541 
542  #define f(j,i) (cooker_.cook((*this)[j][i]))
543  //Using catmull rom interpolation because it doesn't blur at all
544  //bezier curve with intermediate ctrl pts: 0.5/3(p(i+1) - p(i-1)) and similar
545  accumulator_type xfa [4];
546 
547  //precalculate indices (all clamped) and offset
548  const int xi = x > 0 ? (x < w_ ? (int)floor(x) : w_-1) : 0;
549  const int xa[] = {std::max(0,xi-1),xi,std::min(w_-1,xi+1),std::min(w_-1,xi+2)};
550 
551  const int yi = y > 0 ? (y < h_ ? (int)floor(y) : h_-1) : 0;
552  const int ya[] = {std::max(0,yi-1),yi,std::min(h_-1,yi+1),std::min(h_-1,yi+2)};
553 
554  const float xf = x-xi;
555  const float yf = y-yi;
556 
557  //figure polynomials for each point
558  const float txf[] =
559  {
560  0.5f*xf*(xf*(xf*(-1.f) + 2.f) - 1.f), //-t + 2t^2 -t^3
561  0.5f*(xf*(xf*(3.f*xf - 5.f)) + 2.f), //2 - 5t^2 + 3t^3
562  0.5f*xf*(xf*(-3.f*xf + 4.f) + 1.f), //t + 4t^2 - 3t^3
563  0.5f*xf*xf*(xf-1.f) //-t^2 + t^3
564  };
565 
566  const float tyf[] =
567  {
568  0.5f*yf*(yf*(yf*(-1.f) + 2.f) - 1.f), //-t + 2t^2 -t^3
569  0.5f*(yf*(yf*(3.f*yf - 5.f)) + 2.f), //2 - 5t^2 + 3t^3
570  0.5f*yf*(yf*(-3.f*yf + 4.f) + 1.f), //t + 4t^2 - 3t^3
571  0.5f*yf*yf*(yf-1.f) //-t^2 + t^3
572  };
573 
574  //evaluate polynomial for each row
575  for(int i = 0; i < 4; ++i)
576  {
577  xfa[i] = f(ya[i],xa[0])*txf[0] + f(ya[i],xa[1])*txf[1] + f(ya[i],xa[2])*txf[2] + f(ya[i],xa[3])*txf[3];
578  }
579 
580  //return the cumulative column evaluation
581  return cooker_.uncook(xfa[0]*tyf[0] + xfa[1]*tyf[1] + xfa[2]*tyf[2] + xfa[3]*tyf[3]);
582 #undef f
583 #endif
584  }
585 
587  value_type cubic_sample_cooked(float x, float y)const
588  {
589 #define f(j,i) (((accumulator_type)((*this)[j][i])))
590  //Using catmull rom interpolation because it doesn't blur at all
591  //bezier curve with intermediate ctrl pts: 0.5/3(p(i+1) - p(i-1)) and similar
592  accumulator_type xfa [4];
593 
594  //precalculate indices (all clamped) and offset
595  const int xi = x > 0 ? (x < w_ ? (int)floor(x) : w_-1) : 0;
596  const int xa[] = {std::max(0,xi-1),xi,std::min(w_-1,xi+1),std::min(w_-1,xi+2)};
597 
598  const int yi = y > 0 ? (y < h_ ? (int)floor(y) : h_-1) : 0;
599  const int ya[] = {std::max(0,yi-1),yi,std::min(h_-1,yi+1),std::min(h_-1,yi+2)};
600 
601  const float xf = x-xi;
602  const float yf = y-yi;
603 
604  //figure polynomials for each point
605  const float txf[] =
606  {
607  0.5f*xf*(xf*(xf*(-1) + 2) - 1), //-t + 2t^2 -t^3
608  0.5f*(xf*(xf*(3*xf - 5)) + 2), //2 - 5t^2 + 3t^3
609  0.5f*xf*(xf*(-3*xf + 4) + 1), //t + 4t^2 - 3t^3
610  0.5f*xf*xf*(xf-1) //-t^2 + t^3
611  };
612 
613  const float tyf[] =
614  {
615  0.5f*yf*(yf*(yf*(-1.f) + 2.f) - 1.f), //-t + 2t^2 -t^3
616  0.5f*(yf*(yf*(3.f*yf - 5.f)) + 2.f), //2 - 5t^2 + 3t^3
617  0.5f*yf*(yf*(-3.f*yf + 4.f) + 1.f), //t + 4t^2 - 3t^3
618  0.5f*yf*yf*(yf-1.f) //-t^2 + t^3
619  };
620 
621  //evaluate polynomial for each row
622  for(int i = 0; i < 4; ++i)
623  {
624  xfa[i] = f(ya[i],xa[0])*txf[0] + f(ya[i],xa[1])*txf[1] + f(ya[i],xa[2])*txf[2] + f(ya[i],xa[3])*txf[3];
625  }
626 
627  //return the cumulative column evaluation
628  return (value_type)(xfa[0]*tyf[0] + xfa[1]*tyf[1] + xfa[2]*tyf[2] + xfa[3]*tyf[3]);
629 #undef f
630  }
631 
633  value_type sample_rect(float x0,float y0,float x1,float y1) const
634  {
635  const surface &s = *this;
636 
637  //assumes it's clamped to the boundary of the image
638  //force min max relationship for x0,x1 and y0,y1
639  if(x0 > x1) std::swap(x0,x1);
640  if(y0 > y1) std::swap(y0,y1);
641 
642  //local variable madness
643  //all things that want to inter-operate should provide a default value constructor for = 0
644  accumulator_type acum = 0;
645  int xi=0,yi=0;
646 
647  int xib=(int)floor(x0),
648  xie=(int)floor(x1);
649 
650  int yib=(int)floor(y0),
651  yie=(int)floor(y1);
652 
653  //the weight for the pixel should remain the same...
654  float weight = (y1-y0)*(x1-x0);
655  assert(weight != 0);
656 
657  float ylast = y0, xlastb = x0;
658  const_pen pen_ = s.get_pen(xib,yib);
659 
660  for(yi = yib; yi < yie; ylast = ++yi, pen_.inc_y())
661  {
662  const float yweight = yi+1 - ylast;
663 
664  float xlast = xlastb;
665  for(xi = xib; xi < xie; xlast = ++xi, pen_.inc_x())
666  {
667  const float w = yweight*(xi+1 - xlast);
668  acum += cooker_.cook(pen_.get_value())*w;
669  }
670 
671  //post... with next being fractional...
672  const float w = yweight*(x1 - xlast);
673  acum += cooker_.cook(pen_.get_value())*w;
674 
675  pen_.dec_x(xie-xib);
676  }
677 
678  //post in y direction... must have all x...
679  {
680  const float yweight = y1 - ylast;
681 
682  float xlast = xlastb;
683  for(xi = xib; xi < xie; xlast = ++xi)
684  {
685  const float w = yweight*(xi+1 - xlast);
686 
687  acum += cooker_.cook(pen_.get_value())*w;
688  }
689 
690  //post... with next being fractional...
691  const float w = yweight*(x1 - xlast);
692  acum += cooker_.cook(pen_.get_value())*w;
693  }
694 
695  acum *= 1/weight;
696  return cooker_.uncook(acum);
697  }
698 
700  value_type sample_rect_cooked(float x0,float y0,float x1,float y1) const
701  {
702  const surface &s = *this;
703 
704  //assumes it's clamped to the boundary of the image
705  //force min max relationship for x0,x1 and y0,y1
706  if(x0 > x1) std::swap(x0,x1);
707  if(y0 > y1) std::swap(y0,y1);
708 
709  //local variable madness
710  //all things that want to inter-operate should provide a default value constructor for = 0
711  accumulator_type acum = 0;
712  int xi=0,yi=0;
713 
714  int xib=(int)floor(x0),
715  xie=(int)floor(x1);
716 
717  int yib=(int)floor(y0),
718  yie=(int)floor(y1);
719 
720  //the weight for the pixel should remain the same...
721  float weight = (y1-y0)*(x1-x0);
722  assert(weight != 0);
723 
724  float ylast = y0, xlastb = x0;
725  const_pen pen_ = s.get_pen(xib,yib);
726 
727  for(yi = yib; yi < yie; ylast = ++yi, pen_.inc_y())
728  {
729  const float yweight = yi+1 - ylast;
730 
731  float xlast = xlastb;
732  for(xi = xib; xi < xie; xlast = ++xi, pen_.inc_x())
733  {
734  const float w = yweight*(xi+1 - xlast);
735  acum += pen_.get_value()*w;
736  }
737 
738  //post... with next being fractional...
739  const float w = yweight*(x1 - xlast);
740  acum += pen_.get_value()*w;
741 
742  pen_.dec_x(xie-xib);
743  }
744 
745  //post in y direction... must have all x...
746  {
747  const float yweight = y1 - ylast;
748 
749  float xlast = xlastb;
750  for(xi = xib; xi < xie; xlast = ++xi)
751  {
752  const float w = yweight*(xi+1 - xlast);
753 
754  acum += pen_.get_value()*w;
755  }
756 
757  //post... with next being fractional...
758  const float w = yweight*(x1 - xlast);
759  acum += pen_.get_value()*w;
760  }
761 
762  acum *= 1/weight;
763  return (value_type)(acum);
764  }
765 
767  value_type sample_rect_clip(float x0,float y0,float x1,float y1) const
768  {
769  const surface &s = *this;
770 
771  //assumes it's clamped to the boundary of the image
772  //force min max relationship for x0,x1 and y0,y1
773  if(x0 > x1) std::swap(x0,x1);
774  if(y0 > y1) std::swap(y0,y1);
775 
776  //local variable madness
777  //all things that want to inter-operate should provide a default value constructor for = 0
778  accumulator_type acum = 0;
779  int xi=0,yi=0;
780 
781  int xib=(int)floor(x0),
782  xie=(int)floor(x1);
783 
784  int yib=(int)floor(y0),
785  yie=(int)floor(y1);
786 
787  //the weight for the pixel should remain the same...
788  float weight = (y1-y0)*(x1-x0);
789 
790  assert(weight != 0);
791 
792  //clip to the input region
793  if(x0 >= s.get_w() || x1 <= 0) return acum;
794  if(y0 >= s.get_h() || y1 <= 0) return acum;
795 
796  if(x0 < 0) { x0 = 0; xib = 0; }
797  if(x1 >= s.get_w())
798  {
799  x1 = s.get_w(); //want to be just below the last pixel...
800  xie = s.get_w()-1;
801  }
802 
803  if(y0 < 0) { y0 = 0; yib = 0; }
804  if(y1 >= s.get_h())
805  {
806  y1 = s.get_h(); //want to be just below the last pixel...
807  yie = s.get_h()-1;
808  }
809 
810  float ylast = y0, xlastb = x0;
811  const_pen pen = s.get_pen(xib,yib);
812 
813  for(yi = yib; yi < yie; ylast = ++yi, pen.inc_y())
814  {
815  const float yweight = yi+1 - ylast;
816 
817  float xlast = xlastb;
818  for(xi = xib; xi < xie; xlast = ++xi, pen.inc_x())
819  {
820  const float w = yweight*(xi+1 - xlast);
821  acum += cooker_.cook(pen.get_value())*w;
822  }
823 
824  //post... with next being fractional...
825  const float w = yweight*(x1 - xlast);
826  acum += cooker_.cook(pen.get_value())*w;
827 
828  pen.dec_x(xie-xib);
829  }
830 
831  //post in y direction... must have all x...
832  {
833  const float yweight = y1 - ylast;
834 
835  float xlast = xlastb;
836  for(xi = xib; xi < xie; xlast = ++xi)
837  {
838  const float w = yweight*(xi+1 - xlast);
839 
840  acum += cooker_.cook(pen.get_value())*w;
841  }
842 
843  //post... with next being fractional...
844  const float w = yweight*(x1 - xlast);
845  acum += cooker_.cook(pen.get_value())*w;
846  }
847 
848  acum *= 1/weight;
849  return cooker_.uncook(acum);
850  }
851 
853  value_type sample_rect_clip_cooked(float x0,float y0,float x1,float y1) const
854  {
855  const surface &s = *this;
856 
857  //assumes it's clamped to the boundary of the image
858  //force min max relationship for x0,x1 and y0,y1
859  if(x0 > x1) std::swap(x0,x1);
860  if(y0 > y1) std::swap(y0,y1);
861 
862  //local variable madness
863  //all things that want to inter-operate should provide a default value constructor for = 0
864  accumulator_type acum = 0;
865  int xi=0,yi=0;
866 
867  int xib=(int)floor(x0),
868  xie=(int)floor(x1);
869 
870  int yib=(int)floor(y0),
871  yie=(int)floor(y1);
872 
873  //the weight for the pixel should remain the same...
874  float weight = (y1-y0)*(x1-x0);
875 
876  assert(weight != 0);
877 
878  //clip to the input region
879  if(x0 >= s.get_w() || x1 <= 0) return acum;
880  if(y0 >= s.get_h() || y1 <= 0) return acum;
881 
882  if(x0 < 0) { x0 = 0; xib = 0; }
883  if(x1 >= s.get_w())
884  {
885  x1 = s.get_w(); //want to be just below the last pixel...
886  xie = s.get_w()-1;
887  }
888 
889  if(y0 < 0) { y0 = 0; yib = 0; }
890  if(y1 >= s.get_h())
891  {
892  y1 = s.get_h(); //want to be just below the last pixel...
893  yie = s.get_h()-1;
894  }
895 
896  float ylast = y0, xlastb = x0;
897  const_pen pen = s.get_pen(xib,yib);
898 
899  for(yi = yib; yi < yie; ylast = ++yi, pen.inc_y())
900  {
901  const float yweight = yi+1 - ylast;
902 
903  float xlast = xlastb;
904  for(xi = xib; xi < xie; xlast = ++xi, pen.inc_x())
905  {
906  const float w = yweight*(xi+1 - xlast);
907  acum += pen.get_value()*w;
908  }
909 
910  //post... with next being fractional...
911  const float w = yweight*(x1 - xlast);
912  acum += pen.get_value()*w;
913 
914  pen.dec_x(xie-xib);
915  }
916 
917  //post in y direction... must have all x...
918  {
919  const float yweight = y1 - ylast;
920 
921  float xlast = xlastb;
922  for(xi = xib; xi < xie; xlast = ++xi)
923  {
924  const float w = yweight*(xi+1 - xlast);
925 
926  acum += pen.get_value()*w;
927  }
928 
929  //post... with next being fractional...
930  const float w = yweight*(x1 - xlast);
931  acum += pen.get_value()*w;
932  }
933 
934  acum *= 1/weight;
935  return (value_type)(acum);
936  }
937 };
938 
940 
941 /* === T Y P E D E F S ===================================================== */
942 
943 
944 /* === E N D =============================================================== */
945 
946 #endif