1
/*! ========================================================================
2
** Extended Template and Library
3
** Surface Class Implementation
4
** $Id: _surface.h,v 1.1.1.1 2005/01/04 01:31:48 darco Exp $
6
** Copyright (c) 2002 Robert B. Quattlebaum Jr.
8
** This package is free software; you can redistribute it and/or
9
** modify it under the terms of the GNU General Public License as
10
** published by the Free Software Foundation; either version 2 of
11
** the License, or (at your option) any later version.
13
** This package is distributed in the hope that it will be useful,
14
** but WITHOUT ANY WARRANTY; without even the implied warranty of
15
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
** General Public License for more details.
18
** === N O T E S ===========================================================
20
** This is an internal header file, included by other ETL headers.
21
** You should not attempt to use it directly.
23
** ========================================================================= */
25
/* === S T A R T =========================================================== */
27
#ifndef __ETL__SURFACE_H
28
#define __ETL__SURFACE_H
30
/* === H E A D E R S ======================================================= */
34
//#include <algorithm>
36
/* === M A C R O S ========================================================= */
38
/* === C L A S S E S & S T R U C T S ======================================= */
42
template <typename T, typename AT>
47
typedef AT accumulator_type;
49
accumulator_type cook(const value_type& x)const { return (accumulator_type)x; }
50
value_type uncook(const accumulator_type& x)const { return (value_type)x; }
53
template <typename T, typename AT=T, class VP=value_prep<T,AT> >
58
typedef AT accumulator_type;
59
typedef value_type* pointer;
60
typedef const value_type* const_pointer;
61
typedef value_type& reference;
62
typedef generic_pen<value_type,accumulator_type> pen;
63
typedef generic_pen<const value_type,accumulator_type> const_pen;
64
typedef VP value_prep_type;
66
typedef alpha_pen<const_pen> const_alpha_pen;
67
typedef alpha_pen<pen> alpha_pen;
69
typedef typename pen::difference_type size_type;
70
typedef typename pen::difference_type difference_type;
72
typedef typename pen::iterator_x iterator_x;
73
typedef typename pen::iterator_y iterator_y;
74
typedef typename pen::const_iterator_x const_iterator_x;
75
typedef typename pen::const_iterator_y const_iterator_y;
79
value_type *zero_pos_;
80
typename difference_type::value_type pitch_;
84
value_prep_type cooker_;
86
void swap(const surface &x)
88
std::swap(data_,x.data_);
89
std::swap(zero_pos_,x.zero_pos_);
90
std::swap(pitch_,x.pitch_);
93
std::swap(deletable_,x.deletable_);
102
deletable_(false) { }
104
surface(value_type* data, int w, int h, bool deletable=false):
107
pitch_(sizeof(value_type)*w),
109
deletable_(deletable) { }
111
surface(const typename size_type::value_type &w, const typename size_type::value_type &h):
112
data_(new value_type[w*h]),
114
pitch_(sizeof(value_type)*w),
118
surface(const size_type &s):
119
data_(new value_type[s.x*s.y]),
121
pitch_(sizeof(value_type)*s.x),
125
template <typename _pen>
126
surface(const _pen &_begin, const _pen &_end)
128
typename _pen::difference_type size=_end-_begin;
130
data_=new value_type[size.x*size.y];
134
pitch_=sizeof(value_type)*w_;
141
(*this)[y][x]=_begin.get_value_at(x,y);
144
surface(const surface &s):
145
data_(s.data_?new value_type[s.w_*s.h_]:0),
146
zero_pos_(data_+(s.zero_pos_-s.data_)),
150
deletable_(s.data_?true:false)
156
memcpy(data_,s.data_,abs(pitch_)*h_);
169
{ return size_type(w_,h_); }
171
typename size_type::value_type get_pitch()const { return pitch_; }
172
typename size_type::value_type get_w()const { return w_; }
173
typename size_type::value_type get_h()const { return h_; }
175
const surface &mirror(const surface &rhs)
177
if(deletable_)delete [] data_;
180
zero_pos_=rhs.zero_pos_;
189
const surface &operator=(const surface &rhs)
191
set_wh(rhs.w_,rhs.h_);
192
zero_pos_=data_+(rhs.zero_pos_-rhs.data_);
196
memcpy(data_,rhs.data_,pitch_*h_);
202
set_wh(typename size_type::value_type w, typename size_type::value_type h)
206
if(w==w_ && h==h_ && deletable_)
214
pitch_=sizeof(value_type)*w_;
215
zero_pos_=data_=new value_type[h_*w_];
220
fill(value_type v, int x, int y, int w, int h)
223
if(w<=0 || h<=0)return;
225
pen PEN(get_pen(x,y));
227
for(i=0;i<h;i++,PEN.inc_y(),PEN.dec_x(w))
231
template <class _pen> void
232
fill(value_type v, _pen& PEN, int w, int h)
235
if(w<=0 || h<=0)return;
238
for(y=0;y<h;y++,PEN.inc_y(),PEN.dec_x(w))
249
for(y=0;y<h_;y++,pen_.inc_y(),pen_.dec_x(w_))
253
template <class _pen> void blit_to(_pen &pen)
254
{ return blit_to(pen,0,0, get_w(),get_h()); }
256
template <class _pen> void
257
blit_to(_pen &DEST_PEN,
258
int x, int y, int w, int h) //src param
276
//clip width against dest width
277
w = std::min(w,DEST_PEN.end_x()-DEST_PEN.x());
278
h = std::min(h,DEST_PEN.end_y()-DEST_PEN.y());
280
//clip width against src width
281
w = std::min(w,w_-x);
282
h = std::min(h,h_-y);
287
pen SOURCE_PEN(get_pen(x,y));
289
for(; h>0; h--,DEST_PEN.inc_y(),SOURCE_PEN.inc_y())
292
for(i=0; i<w; i++,DEST_PEN.inc_x(),SOURCE_PEN.inc_x())
294
DEST_PEN.put_value(SOURCE_PEN.get_value());
305
if(pitch_==(signed int)sizeof(value_type)*w_)
306
memset(data_,0,h_*pitch_);
312
operator[](const int &y)
313
{ assert(data_); return (pointer)(((char*)zero_pos_)+y*pitch_); }
316
operator[](const int &y)const
317
{ assert(data_); return (const_pointer)(((const char*)zero_pos_)+y*pitch_); }
324
zero_pos_=(pointer)(((char*)zero_pos_)+pitch_*h_);
339
operator bool()const { return is_valid(); }
341
pen begin() { assert(data_); return pen(data_,w_,h_,pitch_); }
342
pen get_pen(int x, int y) { assert(data_); return begin().move(x,y); }
343
pen end() { assert(data_); return get_pen(w_,h_); }
345
const_pen begin()const { assert(data_); return const_pen(data_,w_,h_,pitch_); }
346
const_pen get_pen(int x, int y)const { assert(data_); return begin().move(x,y); }
347
const_pen end()const { assert(data_); return get_pen(w_,h_); }
350
value_type linear_sample(const float x, const float y)const
352
int u(floor_to_int(x)), v(floor_to_int(y));
354
static const float epsilon(1.0e-6);
356
if(x<0.0f)u=0,a=0.0f;
357
else if(x>w_-1)u=w_-1,a=0.0f;
360
if(y<0.0f)v=0,b=0.0f;
361
else if(y>h_-1)v=h_-1,b=0.0f;
365
c(1.0f-a), d(1.0f-b),
366
e(a*d),f(c*b),g(a*b);
368
accumulator_type ret(cooker_.cook((*this)[v][u])*(c*d));
369
if(e>=epsilon)ret+=cooker_.cook((*this)[v][u+1])*e;
370
if(f>=epsilon)ret+=cooker_.cook((*this)[v+1][u])*f;
371
if(g>=epsilon)ret+=cooker_.cook((*this)[v+1][u+1])*g;
372
return cooker_.uncook(ret);
376
value_type cosine_sample(const float x, const float y)const
378
int u(floor_to_int(x)), v(floor_to_int(y));
380
static const float epsilon(1.0e-6);
382
if(x<0.0f)u=0,a=0.0f;
383
else if(x>w_-1)u=w_-1,a=0.0f;
386
if(y<0.0f)v=0,b=0.0f;
387
else if(y>h_-1)v=h_-1,b=0.0f;
390
a=(1.0f-cos(a*3.1415927f))*0.5f;
391
b=(1.0f-cos(b*3.1415927f))*0.5f;
394
c(1.0f-a), d(1.0f-b),
395
e(a*d),f(c*b),g(a*b);
397
accumulator_type ret(cooker_.cook((*this)[v][u])*(c*d));
398
if(e>=epsilon)ret+=cooker_.cook((*this)[v][u+1])*e;
399
if(f>=epsilon)ret+=cooker_.cook((*this)[v+1][u])*f;
400
if(g>=epsilon)ret+=cooker_.cook((*this)[v+1][u+1])*g;
402
return cooker_.uncook(ret);
406
value_type cubic_sample(float x, float y)const
409
#define P(x) (((x)>=0)?((x)*(x)*(x)):0.0f)
410
#define R(x) ( P(x+2) - 4.0f*P(x+1) + 6.0f*P(x) - 4.0f*P(x-1) )*(1.0f/6.0f)
411
#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))))
412
#define Z(i,j) ret+=F(i,j)
413
#define X(i,j) // placeholder... To make box more symetric
415
int u(floor_to_int(x)), v(floor_to_int(y));
419
if(x<0.0f)u=0,a=0.0f;
420
else if(u>w_-1)u=w_-1,a=0.0f;
424
if(y<0.0f)v=0,b=0.0f;
425
else if(v>h_-1)v=h_-1,b=0.0f;
429
accumulator_type ret(F(0,0));
430
Z(-1,-1); Z(-1, 0); Z(-1, 1); Z(-1, 2);
431
Z( 0,-1); X( 0, 0); Z( 0, 1); Z( 0, 2);
432
Z( 1,-1); Z( 1, 0); Z( 1, 1); Z( 1, 2);
433
Z( 2,-1); Z( 2, 0); Z( 2, 1); Z( 2, 2);
435
return cooker_.uncook(ret);
444
#define f(j,i) (cooker_.cook((*this)[j][i]))
445
//Using catmull rom interpolation because it doesn't blur at all
446
//bezier curve with intermediate ctrl pts: 0.5/3(p(i+1) - p(i-1)) and similar
447
accumulator_type xfa [4];
449
//precalculate indices (all clamped) and offset
450
const int xi = x > 0 ? (x < w_ ? (int)floor(x) : w_-1) : 0;
451
const int xa[] = {std::max(0,xi-1),xi,std::min(w_-1,xi+1),std::min(w_-1,xi+2)};
453
const int yi = y > 0 ? (y < h_ ? (int)floor(y) : h_-1) : 0;
454
const int ya[] = {std::max(0,yi-1),yi,std::min(h_-1,yi+1),std::min(h_-1,yi+2)};
456
const float xf = x-xi;
457
const float yf = y-yi;
459
//figure polynomials for each point
462
0.5*xf*(xf*(xf*(-1) + 2) - 1), //-t + 2t^2 -t^3
463
0.5*(xf*(xf*(3*xf - 5)) + 2), //2 - 5t^2 + 3t^3
464
0.5*xf*(xf*(-3*xf + 4) + 1), //t + 4t^2 - 3t^3
465
0.5*xf*xf*(xf-1) //-t^2 + t^3
470
0.5*yf*(yf*(yf*(-1) + 2) - 1), //-t + 2t^2 -t^3
471
0.5*(yf*(yf*(3*yf - 5)) + 2), //2 - 5t^2 + 3t^3
472
0.5*yf*(yf*(-3*yf + 4) + 1), //t + 4t^2 - 3t^3
473
0.5*yf*yf*(yf-1) //-t^2 + t^3
476
//evaluate polynomial for each row
477
for(int i = 0; i < 4; ++i)
479
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];
482
//return the cumulative column evaluation
483
return cooker_.uncook(xfa[0]*tyf[0] + xfa[1]*tyf[1] + xfa[2]*tyf[2] + xfa[3]*tyf[3]);
488
value_type sample_rect(float x0,float y0,float x1,float y1) const
490
const surface &s = *this;
492
//assumes it's clamped to the boundary of the image
493
//force min max relationship for x0,x1 and y0,y1
494
if(x0 > x1) std::swap(x0,x1);
495
if(y0 > y1) std::swap(y0,y1);
497
//local variable madness
498
//all things that want to interoperate should provide a default value constructor for = 0
499
accumulator_type acum = 0;
502
int xib=(int)floor(x0),
505
int yib=(int)floor(y0),
508
//the weight for the pixel should remain the same...
509
float weight = (y1-y0)*(x1-x0);
512
float ylast = y0, xlastb = x0;
513
const_pen pen_ = s.get_pen(xib,yib);
515
for(yi = yib; yi < yie; ylast = ++yi, pen_.inc_y())
517
const float yweight = yi+1 - ylast;
519
float xlast = xlastb;
520
for(xi = xib; xi < xie; xlast = ++xi, pen_.inc_x())
522
const float w = yweight*(xi+1 - xlast);
523
acum += cooker_.cook(pen_.get_value())*w;
526
//post... with next being fractional...
527
const float w = yweight*(x1 - xlast);
528
acum += cooker_.cook(pen_.get_value())*w;
533
//post in y direction... must have all x...
535
const float yweight = y1 - ylast;
537
float xlast = xlastb;
538
for(xi = xib; xi < xie; xlast = ++xi)
540
const float w = yweight*(xi+1 - xlast);
542
acum += cooker_.cook(pen_.get_value())*w;
545
//post... with next being fractional...
546
const float w = yweight*(x1 - xlast);
547
acum += cooker_.cook(pen_.get_value())*w;
551
return cooker_.uncook(acum);
554
value_type sample_rect_clip(float x0,float y0,float x1,float y1) const
556
const surface &s = *this;
558
//assumes it's clamped to the boundary of the image
559
//force min max relationship for x0,x1 and y0,y1
560
if(x0 > x1) std::swap(x0,x1);
561
if(y0 > y1) std::swap(y0,y1);
563
//local variable madness
564
//all things that want to interoperate should provide a default value constructor for = 0
565
accumulator_type acum = 0;
568
int xib=(int)floor(x0),
571
int yib=(int)floor(y0),
574
//the weight for the pixel should remain the same...
575
float weight = (y1-y0)*(x1-x0);
579
//clip to the input region
580
if(x0 >= s.get_w() || x1 <= 0) return acum;
581
if(y0 >= s.get_h() || y1 <= 0) return acum;
583
if(x0 < 0) { x0 = 0; xib = 0; }
586
x1 = s.get_w(); //want to be just below the last pixel...
590
if(y0 < 0) { y0 = 0; yib = 0; }
593
y1 = s.get_h(); //want to be just below the last pixel...
597
float ylast = y0, xlastb = x0;
598
const_pen pen = s.get_pen(xib,yib);
600
for(yi = yib; yi < yie; ylast = ++yi, pen.inc_y())
602
const float yweight = yi+1 - ylast;
604
float xlast = xlastb;
605
for(xi = xib; xi < xie; xlast = ++xi, pen.inc_x())
607
const float w = yweight*(xi+1 - xlast);
608
acum += cooker_.cook(pen.get_value())*w;
611
//post... with next being fractional...
612
const float w = yweight*(x1 - xlast);
613
acum += cooker_.cook(pen.get_value())*w;
618
//post in y direction... must have all x...
620
const float yweight = y1 - ylast;
622
float xlast = xlastb;
623
for(xi = xib; xi < xie; xlast = ++xi)
625
const float w = yweight*(xi+1 - xlast);
627
acum += cooker_.cook(pen.get_value())*w;
630
//post... with next being fractional...
631
const float w = yweight*(x1 - xlast);
632
acum += cooker_.cook(pen.get_value())*w;
636
return cooker_.uncook(acum);
642
/* === T Y P E D E F S ===================================================== */
645
/* === E N D =============================================================== */