00001
00025
00026
00027 #ifndef __ETL__SURFACE_H
00028 #define __ETL__SURFACE_H
00029
00030
00031
00032 #include "_pen.h"
00033 #include "_misc.h"
00034
00035
00036
00037
00038
00039
00040 _ETL_BEGIN_NAMESPACE
00041
00042 template <typename T, typename AT>
00043 class value_prep
00044 {
00045 public:
00046 typedef T value_type;
00047 typedef AT accumulator_type;
00048
00049 accumulator_type cook(const value_type& x)const { return (accumulator_type)x; }
00050 value_type uncook(const accumulator_type& x)const { return (value_type)x; }
00051 };
00052
00053 template <typename T, typename AT=T, class VP=value_prep<T,AT> >
00054 class surface
00055 {
00056 public:
00057 typedef T value_type;
00058 typedef AT accumulator_type;
00059 typedef value_type* pointer;
00060 typedef const value_type* const_pointer;
00061 typedef value_type& reference;
00062 typedef generic_pen<value_type,accumulator_type> pen;
00063 typedef generic_pen<const value_type,accumulator_type> const_pen;
00064 typedef VP value_prep_type;
00065
00066 typedef alpha_pen<const_pen> const_alpha_pen;
00067 typedef alpha_pen<pen> alpha_pen;
00068
00069 typedef typename pen::difference_type size_type;
00070 typedef typename pen::difference_type difference_type;
00071
00072 typedef typename pen::iterator_x iterator_x;
00073 typedef typename pen::iterator_y iterator_y;
00074 typedef typename pen::const_iterator_x const_iterator_x;
00075 typedef typename pen::const_iterator_y const_iterator_y;
00076
00077 private:
00078 value_type *data_;
00079 value_type *zero_pos_;
00080 typename difference_type::value_type pitch_;
00081 int w_, h_;
00082 bool deletable_;
00083
00084 value_prep_type cooker_;
00085
00086 void swap(const surface &x)
00087 {
00088 std::swap(data_,x.data_);
00089 std::swap(zero_pos_,x.zero_pos_);
00090 std::swap(pitch_,x.pitch_);
00091 std::swap(w_,x.w_);
00092 std::swap(h_,x.h_);
00093 std::swap(deletable_,x.deletable_);
00094 }
00095
00096 public:
00097 surface():
00098 data_(0),
00099 zero_pos_(data_),
00100 pitch_(0),
00101 w_(0),h_(0),
00102 deletable_(false) { }
00103
00104 surface(value_type* data, int w, int h, bool deletable=false):
00105 data_(data),
00106 zero_pos_(data),
00107 pitch_(sizeof(value_type)*w),
00108 w_(w),h_(h),
00109 deletable_(deletable) { }
00110
00111 surface(const typename size_type::value_type &w, const typename size_type::value_type &h):
00112 data_(new value_type[w*h]),
00113 zero_pos_(data_),
00114 pitch_(sizeof(value_type)*w),
00115 w_(w),h_(h),
00116 deletable_(true) { }
00117
00118 surface(const size_type &s):
00119 data_(new value_type[s.x*s.y]),
00120 zero_pos_(data_),
00121 pitch_(sizeof(value_type)*s.x),
00122 w_(s.x),h_(s.y),
00123 deletable_(true) { }
00124
00125 template <typename _pen>
00126 surface(const _pen &_begin, const _pen &_end)
00127 {
00128 typename _pen::difference_type size=_end-_begin;
00129
00130 data_=new value_type[size.x*size.y];
00131 w_=size.x;
00132 h_=size.y;
00133 zero_pos_=data_;
00134 pitch_=sizeof(value_type)*w_;
00135 deletable_=true;
00136
00137 int x,y;
00138
00139 for(y=0;y<h_;y++)
00140 for(x=0;x<w_;x++)
00141 (*this)[y][x]=_begin.get_value_at(x,y);
00142 }
00143
00144 surface(const surface &s):
00145 data_(s.data_?new value_type[s.w_*s.h_]:0),
00146 zero_pos_(data_+(s.zero_pos_-s.data_)),
00147 pitch_(s.pitch_),
00148 w_(s.w_),
00149 h_(s.h_),
00150 deletable_(s.data_?true:false)
00151 {
00152 assert(&s);
00153 if(s.data_)
00154 {
00155 assert(data_);
00156 memcpy(data_,s.data_,abs(pitch_)*h_);
00157 }
00158 }
00159
00160 public:
00161 ~surface()
00162 {
00163 if(deletable_)
00164 delete [] data_;
00165 }
00166
00167 size_type
00168 size()const
00169 { return size_type(w_,h_); }
00170
00171 typename size_type::value_type get_pitch()const { return pitch_; }
00172 typename size_type::value_type get_w()const { return w_; }
00173 typename size_type::value_type get_h()const { return h_; }
00174
00175 const surface &mirror(const surface &rhs)
00176 {
00177 if(deletable_)delete [] data_;
00178
00179 data_=rhs.data_;
00180 zero_pos_=rhs.zero_pos_;
00181 pitch_=rhs.pitch_;
00182 w_=rhs.w_;
00183 h_=rhs.h_;
00184 deletable_=false;
00185
00186 return *this;
00187 }
00188
00189 const surface &operator=(const surface &rhs)
00190 {
00191 set_wh(rhs.w_,rhs.h_);
00192 zero_pos_=data_+(rhs.zero_pos_-rhs.data_);
00193 pitch_=rhs.pitch_;
00194 deletable_=true;
00195
00196 memcpy(data_,rhs.data_,pitch_*h_);
00197
00198 return *this;
00199 }
00200
00201 void
00202 set_wh(typename size_type::value_type w, typename size_type::value_type h)
00203 {
00204 if(data_)
00205 {
00206 if(w==w_ && h==h_ && deletable_)
00207 return;
00208 if(deletable_)
00209 delete [] data_;
00210 }
00211
00212 w_=w;
00213 h_=h;
00214 pitch_=sizeof(value_type)*w_;
00215 zero_pos_=data_=new value_type[h_*w_];
00216 deletable_=true;
00217 }
00218
00219 void
00220 fill(value_type v, int x, int y, int w, int h)
00221 {
00222 assert(data_);
00223 if(w<=0 || h<=0)return;
00224 int i;
00225 pen PEN(get_pen(x,y));
00226 PEN.set_value(v);
00227 for(i=0;i<h;i++,PEN.inc_y(),PEN.dec_x(w))
00228 PEN.put_hline(w);
00229 }
00230
00231 template <class _pen> void
00232 fill(value_type v, _pen& PEN, int w, int h)
00233 {
00234 assert(data_);
00235 if(w<=0 || h<=0)return;
00236 int y;
00237 PEN.set_value(v);
00238 for(y=0;y<h;y++,PEN.inc_y(),PEN.dec_x(w))
00239 PEN.put_hline(w);
00240 }
00241
00242 void
00243 fill(value_type v)
00244 {
00245 assert(data_);
00246 int y;
00247 pen pen_=begin();
00248 pen_.set_value(v);
00249 for(y=0;y<h_;y++,pen_.inc_y(),pen_.dec_x(w_))
00250 pen_.put_hline(w_);
00251 }
00252
00253 template <class _pen> void blit_to(_pen &pen)
00254 { return blit_to(pen,0,0, get_w(),get_h()); }
00255
00256 template <class _pen> void
00257 blit_to(_pen &DEST_PEN,
00258 int x, int y, int w, int h)
00259 {
00260 if(x>=w_ || y>=h_)
00261 return;
00262
00263
00264 if(x<0)
00265 {
00266 w+=x;
00267 x=0;
00268 }
00269
00270 if(y<0)
00271 {
00272 h+=y;
00273 y=0;
00274 }
00275
00276
00277 w = std::min(w,DEST_PEN.end_x()-DEST_PEN.x());
00278 h = std::min(h,DEST_PEN.end_y()-DEST_PEN.y());
00279
00280
00281 w = std::min(w,w_-x);
00282 h = std::min(h,h_-y);
00283
00284 if(w<=0 || h<=0)
00285 return;
00286
00287 pen SOURCE_PEN(get_pen(x,y));
00288
00289 for(; h>0; h--,DEST_PEN.inc_y(),SOURCE_PEN.inc_y())
00290 {
00291 int i;
00292 for(i=0; i<w; i++,DEST_PEN.inc_x(),SOURCE_PEN.inc_x())
00293 {
00294 DEST_PEN.put_value(SOURCE_PEN.get_value());
00295 }
00296 DEST_PEN.dec_x(w);
00297 SOURCE_PEN.dec_x(w);
00298 }
00299 }
00300
00301 void
00302 clear()
00303 {
00304 assert(data_);
00305 if(pitch_==(signed int)sizeof(value_type)*w_)
00306 memset(data_,0,h_*pitch_);
00307 else
00308 fill(value_type());
00309 }
00310
00311 iterator_x
00312 operator[](const int &y)
00313 { assert(data_); return (pointer)(((char*)zero_pos_)+y*pitch_); }
00314
00315 const_iterator_x
00316 operator[](const int &y)const
00317 { assert(data_); return (const_pointer)(((const char*)zero_pos_)+y*pitch_); }
00318
00319 void
00320 flip_v()
00321 {
00322 assert(data_);
00323
00324 zero_pos_=(pointer)(((char*)zero_pos_)+pitch_*h_);
00325
00326 pitch_=-pitch_;
00327 }
00328
00329 bool is_valid()const
00330 {
00331 return data_!=0
00332 && zero_pos_!=0
00333 && w_>0
00334 && h_>0
00335 && pitch_!=0
00336 ;
00337 }
00338
00339 operator bool()const { return is_valid(); }
00340
00341 pen begin() { assert(data_); return pen(data_,w_,h_,pitch_); }
00342 pen get_pen(int x, int y) { assert(data_); return begin().move(x,y); }
00343 pen end() { assert(data_); return get_pen(w_,h_); }
00344
00345 const_pen begin()const { assert(data_); return const_pen(data_,w_,h_,pitch_); }
00346 const_pen get_pen(int x, int y)const { assert(data_); return begin().move(x,y); }
00347 const_pen end()const { assert(data_); return get_pen(w_,h_); }
00348
00350 value_type linear_sample(const float x, const float y)const
00351 {
00352 int u(floor_to_int(x)), v(floor_to_int(y));
00353 float a, b;
00354 static const float epsilon(1.0e-6);
00355
00356 if(x<0.0f)u=0,a=0.0f;
00357 else if(x>w_-1)u=w_-1,a=0.0f;
00358 else a=x-u;
00359
00360 if(y<0.0f)v=0,b=0.0f;
00361 else if(y>h_-1)v=h_-1,b=0.0f;
00362 else b=y-v;
00363
00364 const float
00365 c(1.0f-a), d(1.0f-b),
00366 e(a*d),f(c*b),g(a*b);
00367
00368 accumulator_type ret(cooker_.cook((*this)[v][u])*(c*d));
00369 if(e>=epsilon)ret+=cooker_.cook((*this)[v][u+1])*e;
00370 if(f>=epsilon)ret+=cooker_.cook((*this)[v+1][u])*f;
00371 if(g>=epsilon)ret+=cooker_.cook((*this)[v+1][u+1])*g;
00372 return cooker_.uncook(ret);
00373 }
00374
00376 value_type cosine_sample(const float x, const float y)const
00377 {
00378 int u(floor_to_int(x)), v(floor_to_int(y));
00379 float a, b;
00380 static const float epsilon(1.0e-6);
00381
00382 if(x<0.0f)u=0,a=0.0f;
00383 else if(x>w_-1)u=w_-1,a=0.0f;
00384 else a=x-u;
00385
00386 if(y<0.0f)v=0,b=0.0f;
00387 else if(y>h_-1)v=h_-1,b=0.0f;
00388 else b=y-v;
00389
00390 a=(1.0f-cos(a*3.1415927f))*0.5f;
00391 b=(1.0f-cos(b*3.1415927f))*0.5f;
00392
00393 const float
00394 c(1.0f-a), d(1.0f-b),
00395 e(a*d),f(c*b),g(a*b);
00396
00397 accumulator_type ret(cooker_.cook((*this)[v][u])*(c*d));
00398 if(e>=epsilon)ret+=cooker_.cook((*this)[v][u+1])*e;
00399 if(f>=epsilon)ret+=cooker_.cook((*this)[v+1][u])*f;
00400 if(g>=epsilon)ret+=cooker_.cook((*this)[v+1][u+1])*g;
00401
00402 return cooker_.uncook(ret);
00403 }
00404
00406 value_type cubic_sample(float x, float y)const
00407 {
00408 #if 0
00409 #define P(x) (((x)>=0)?((x)*(x)*(x)):0.0f)
00410 #define R(x) ( P(x+2) - 4.0f*P(x+1) + 6.0f*P(x) - 4.0f*P(x-1) )*(1.0f/6.0f)
00411 #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))))
00412 #define Z(i,j) ret+=F(i,j)
00413 #define X(i,j) // placeholder... To make box more symetric
00414
00415 int u(floor_to_int(x)), v(floor_to_int(y));
00416 float a, b;
00417
00418
00419 if(x<0.0f)u=0,a=0.0f;
00420 else if(u>w_-1)u=w_-1,a=0.0f;
00421 else a=x-u;
00422
00423
00424 if(y<0.0f)v=0,b=0.0f;
00425 else if(v>h_-1)v=h_-1,b=0.0f;
00426 else b=y-v;
00427
00428
00429 accumulator_type ret(F(0,0));
00430 Z(-1,-1); Z(-1, 0); Z(-1, 1); Z(-1, 2);
00431 Z( 0,-1); X( 0, 0); Z( 0, 1); Z( 0, 2);
00432 Z( 1,-1); Z( 1, 0); Z( 1, 1); Z( 1, 2);
00433 Z( 2,-1); Z( 2, 0); Z( 2, 1); Z( 2, 2);
00434
00435 return cooker_.uncook(ret);
00436
00437 #undef X
00438 #undef Z
00439 #undef F
00440 #undef P
00441 #undef R
00442 #else
00443
00444 #define f(j,i) (cooker_.cook((*this)[j][i]))
00445
00446
00447 accumulator_type xfa [4];
00448
00449
00450 const int xi = x > 0 ? (x < w_ ? (int)floor(x) : w_-1) : 0;
00451 const int xa[] = {std::max(0,xi-1),xi,std::min(w_-1,xi+1),std::min(w_-1,xi+2)};
00452
00453 const int yi = y > 0 ? (y < h_ ? (int)floor(y) : h_-1) : 0;
00454 const int ya[] = {std::max(0,yi-1),yi,std::min(h_-1,yi+1),std::min(h_-1,yi+2)};
00455
00456 const float xf = x-xi;
00457 const float yf = y-yi;
00458
00459
00460 const float txf[] =
00461 {
00462 0.5*xf*(xf*(xf*(-1) + 2) - 1),
00463 0.5*(xf*(xf*(3*xf - 5)) + 2),
00464 0.5*xf*(xf*(-3*xf + 4) + 1),
00465 0.5*xf*xf*(xf-1)
00466 };
00467
00468 const float tyf[] =
00469 {
00470 0.5*yf*(yf*(yf*(-1) + 2) - 1),
00471 0.5*(yf*(yf*(3*yf - 5)) + 2),
00472 0.5*yf*(yf*(-3*yf + 4) + 1),
00473 0.5*yf*yf*(yf-1)
00474 };
00475
00476
00477 for(int i = 0; i < 4; ++i)
00478 {
00479 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];
00480 }
00481
00482
00483 return cooker_.uncook(xfa[0]*tyf[0] + xfa[1]*tyf[1] + xfa[2]*tyf[2] + xfa[3]*tyf[3]);
00484 #undef f
00485 #endif
00486 }
00487
00488 value_type sample_rect(float x0,float y0,float x1,float y1) const
00489 {
00490 const surface &s = *this;
00491
00492
00493
00494 if(x0 > x1) std::swap(x0,x1);
00495 if(y0 > y1) std::swap(y0,y1);
00496
00497
00498
00499 accumulator_type acum = 0;
00500 int xi=0,yi=0;
00501
00502 int xib=(int)floor(x0),
00503 xie=(int)floor(x1);
00504
00505 int yib=(int)floor(y0),
00506 yie=(int)floor(y1);
00507
00508
00509 float weight = (y1-y0)*(x1-x0);
00510 assert(weight != 0);
00511
00512 float ylast = y0, xlastb = x0;
00513 const_pen pen_ = s.get_pen(xib,yib);
00514
00515 for(yi = yib; yi < yie; ylast = ++yi, pen_.inc_y())
00516 {
00517 const float yweight = yi+1 - ylast;
00518
00519 float xlast = xlastb;
00520 for(xi = xib; xi < xie; xlast = ++xi, pen_.inc_x())
00521 {
00522 const float w = yweight*(xi+1 - xlast);
00523 acum += cooker_.cook(pen_.get_value())*w;
00524 }
00525
00526
00527 const float w = yweight*(x1 - xlast);
00528 acum += cooker_.cook(pen_.get_value())*w;
00529
00530 pen_.dec_x(xie-xib);
00531 }
00532
00533
00534 {
00535 const float yweight = y1 - ylast;
00536
00537 float xlast = xlastb;
00538 for(xi = xib; xi < xie; xlast = ++xi)
00539 {
00540 const float w = yweight*(xi+1 - xlast);
00541
00542 acum += cooker_.cook(pen_.get_value())*w;
00543 }
00544
00545
00546 const float w = yweight*(x1 - xlast);
00547 acum += cooker_.cook(pen_.get_value())*w;
00548 }
00549
00550 acum *= 1/weight;
00551 return cooker_.uncook(acum);
00552 }
00553
00554 value_type sample_rect_clip(float x0,float y0,float x1,float y1) const
00555 {
00556 const surface &s = *this;
00557
00558
00559
00560 if(x0 > x1) std::swap(x0,x1);
00561 if(y0 > y1) std::swap(y0,y1);
00562
00563
00564
00565 accumulator_type acum = 0;
00566 int xi=0,yi=0;
00567
00568 int xib=(int)floor(x0),
00569 xie=(int)floor(x1);
00570
00571 int yib=(int)floor(y0),
00572 yie=(int)floor(y1);
00573
00574
00575 float weight = (y1-y0)*(x1-x0);
00576
00577 assert(weight != 0);
00578
00579
00580 if(x0 >= s.get_w() || x1 <= 0) return acum;
00581 if(y0 >= s.get_h() || y1 <= 0) return acum;
00582
00583 if(x0 < 0) { x0 = 0; xib = 0; }
00584 if(x1 >= s.get_w())
00585 {
00586 x1 = s.get_w();
00587 xie = s.get_w()-1;
00588 }
00589
00590 if(y0 < 0) { y0 = 0; yib = 0; }
00591 if(y1 >= s.get_h())
00592 {
00593 y1 = s.get_h();
00594 yie = s.get_h()-1;
00595 }
00596
00597 float ylast = y0, xlastb = x0;
00598 const_pen pen = s.get_pen(xib,yib);
00599
00600 for(yi = yib; yi < yie; ylast = ++yi, pen.inc_y())
00601 {
00602 const float yweight = yi+1 - ylast;
00603
00604 float xlast = xlastb;
00605 for(xi = xib; xi < xie; xlast = ++xi, pen.inc_x())
00606 {
00607 const float w = yweight*(xi+1 - xlast);
00608 acum += cooker_.cook(pen.get_value())*w;
00609 }
00610
00611
00612 const float w = yweight*(x1 - xlast);
00613 acum += cooker_.cook(pen.get_value())*w;
00614
00615 pen.dec_x(xie-xib);
00616 }
00617
00618
00619 {
00620 const float yweight = y1 - ylast;
00621
00622 float xlast = xlastb;
00623 for(xi = xib; xi < xie; xlast = ++xi)
00624 {
00625 const float w = yweight*(xi+1 - xlast);
00626
00627 acum += cooker_.cook(pen.get_value())*w;
00628 }
00629
00630
00631 const float w = yweight*(x1 - xlast);
00632 acum += cooker_.cook(pen.get_value())*w;
00633 }
00634
00635 acum *= 1/weight;
00636 return cooker_.uncook(acum);
00637 }
00638 };
00639
00640 _ETL_END_NAMESPACE
00641
00642
00643
00644
00645
00646
00647 #endif