Author: Carlos Lopez <genet...@gmail.com> Date: Thu Sep 6 20:35:50 2012 +0200
etl::surface: normal sample functions assumes that the surface's content is a value that is not "cooked" (premultiplied for colors). Add proper functions to sample a point when the surface is already "cooked" --- ETL/ETL/_surface.h | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 257 insertions(+), 0 deletions(-) diff --git a/ETL/ETL/_surface.h b/ETL/ETL/_surface.h index 06c2109..a1f6d6b 100644 --- a/ETL/ETL/_surface.h +++ b/ETL/ETL/_surface.h @@ -398,6 +398,32 @@ public: return cooker_.uncook(ret); } + //! Linear sample for already "cooked" surfaces + value_type linear_sample_cooked(const float x, const float y)const + { + int u(floor_to_int(x)), v(floor_to_int(y)); + float a, b; + static const float epsilon(1.0e-6); + + if(x<0.0f)u=0,a=0.0f; + else if(x>w_-1)u=w_-1,a=0.0f; + else a=x-u; + + if(y<0.0f)v=0,b=0.0f; + else if(y>h_-1)v=h_-1,b=0.0f; + else b=y-v; + + const float + c(1.0f-a), d(1.0f-b), + e(a*d),f(c*b),g(a*b); + + accumulator_type ret((*this)[v][u]*(c*d)); + if(e>=epsilon)ret+=(*this)[v][u+1]*e; + if(f>=epsilon)ret+=(*this)[v+1][u]*f; + if(g>=epsilon)ret+=(*this)[v+1][u+1]*g; + return ret; + } + //! Cosine sample value_type cosine_sample(const float x, const float y)const { @@ -428,6 +454,36 @@ public: return cooker_.uncook(ret); } + //! Cosine sample for already "cooked" surfaces + value_type cosine_sample_cooked(const float x, const float y)const + { + int u(floor_to_int(x)), v(floor_to_int(y)); + float a, b; + static const float epsilon(1.0e-6); + + if(x<0.0f)u=0,a=0.0f; + else if(x>w_-1)u=w_-1,a=0.0f; + else a=x-u; + + if(y<0.0f)v=0,b=0.0f; + else if(y>h_-1)v=h_-1,b=0.0f; + else b=y-v; + + a=(1.0f-cos(a*3.1415927f))*0.5f; + b=(1.0f-cos(b*3.1415927f))*0.5f; + + const float + c(1.0f-a), d(1.0f-b), + e(a*d),f(c*b),g(a*b); + + accumulator_type ret((*this)[v][u]*(c*d)); + if(e>=epsilon)ret+=(*this)[v][u+1]*e; + if(f>=epsilon)ret+=(*this)[v+1][u]*f; + if(g>=epsilon)ret+=(*this)[v+1][u+1]*g; + + return ret; + } + //! Cubic sample value_type cubic_sample(float x, float y)const { @@ -511,6 +567,53 @@ public: #endif } + //! Cubic sample for already "cooked" surfaces + value_type cubic_sample_cooked(float x, float y)const + { +#define f(j,i) (((*this)[j][i])) + //Using catmull rom interpolation because it doesn't blur at all + //bezier curve with intermediate ctrl pts: 0.5/3(p(i+1) - p(i-1)) and similar + accumulator_type xfa [4]; + + //precalculate indices (all clamped) and offset + const int xi = x > 0 ? (x < w_ ? (int)floor(x) : w_-1) : 0; + const int xa[] = {std::max(0,xi-1),xi,std::min(w_-1,xi+1),std::min(w_-1,xi+2)}; + + const int yi = y > 0 ? (y < h_ ? (int)floor(y) : h_-1) : 0; + const int ya[] = {std::max(0,yi-1),yi,std::min(h_-1,yi+1),std::min(h_-1,yi+2)}; + + const float xf = x-xi; + const float yf = y-yi; + + //figure polynomials for each point + const float txf[] = + { + 0.5*xf*(xf*(xf*(-1) + 2) - 1), //-t + 2t^2 -t^3 + 0.5*(xf*(xf*(3*xf - 5)) + 2), //2 - 5t^2 + 3t^3 + 0.5*xf*(xf*(-3*xf + 4) + 1), //t + 4t^2 - 3t^3 + 0.5*xf*xf*(xf-1) //-t^2 + t^3 + }; + + const float tyf[] = + { + 0.5*yf*(yf*(yf*(-1) + 2) - 1), //-t + 2t^2 -t^3 + 0.5*(yf*(yf*(3*yf - 5)) + 2), //2 - 5t^2 + 3t^3 + 0.5*yf*(yf*(-3*yf + 4) + 1), //t + 4t^2 - 3t^3 + 0.5*yf*yf*(yf-1) //-t^2 + t^3 + }; + + //evaluate polynomial for each row + for(int i = 0; i < 4; ++i) + { + 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]; + } + + //return the cumulative column evaluation + return xfa[0]*tyf[0] + xfa[1]*tyf[1] + xfa[2]*tyf[2] + xfa[3]*tyf[3]; +#undef f + } + + //! Rectangle sample value_type sample_rect(float x0,float y0,float x1,float y1) const { const surface &s = *this; @@ -577,6 +680,74 @@ public: return cooker_.uncook(acum); } + //! Rectangle sample for already "cooked" surfaces + value_type sample_rect_cooked(float x0,float y0,float x1,float y1) const + { + const surface &s = *this; + + //assumes it's clamped to the boundary of the image + //force min max relationship for x0,x1 and y0,y1 + if(x0 > x1) std::swap(x0,x1); + if(y0 > y1) std::swap(y0,y1); + + //local variable madness + //all things that want to inter-operate should provide a default value constructor for = 0 + accumulator_type acum = 0; + int xi=0,yi=0; + + int xib=(int)floor(x0), + xie=(int)floor(x1); + + int yib=(int)floor(y0), + yie=(int)floor(y1); + + //the weight for the pixel should remain the same... + float weight = (y1-y0)*(x1-x0); + assert(weight != 0); + + float ylast = y0, xlastb = x0; + const_pen pen_ = s.get_pen(xib,yib); + + for(yi = yib; yi < yie; ylast = ++yi, pen_.inc_y()) + { + const float yweight = yi+1 - ylast; + + float xlast = xlastb; + for(xi = xib; xi < xie; xlast = ++xi, pen_.inc_x()) + { + const float w = yweight*(xi+1 - xlast); + acum += pen_.get_value()*w; + } + + //post... with next being fractional... + const float w = yweight*(x1 - xlast); + acum += pen_.get_value()*w; + + pen_.dec_x(xie-xib); + } + + //post in y direction... must have all x... + { + const float yweight = y1 - ylast; + + float xlast = xlastb; + for(xi = xib; xi < xie; xlast = ++xi) + { + const float w = yweight*(xi+1 - xlast); + + acum += pen_.get_value()*w; + } + + //post... with next being fractional... + const float w = yweight*(x1 - xlast); + acum += pen_.get_value()*w; + } + + acum *= 1/weight; + return acum; + } + + //! Rectangle sample clipped value_type sample_rect_clip(float x0,float y0,float x1,float y1) const { const surface &s = *this; @@ -661,6 +832,92 @@ public: acum *= 1/weight; return cooker_.uncook(acum); } + + //! Rectangle sample clipped for already "cooked" surfaces + value_type sample_rect_clip_cooked(float x0,float y0,float x1,float y1) const + { + const surface &s = *this; + + //assumes it's clamped to the boundary of the image + //force min max relationship for x0,x1 and y0,y1 + if(x0 > x1) std::swap(x0,x1); + if(y0 > y1) std::swap(y0,y1); + + //local variable madness + //all things that want to inter-operate should provide a default value constructor for = 0 + accumulator_type acum = 0; + int xi=0,yi=0; + + int xib=(int)floor(x0), + xie=(int)floor(x1); + + int yib=(int)floor(y0), + yie=(int)floor(y1); + + //the weight for the pixel should remain the same... + float weight = (y1-y0)*(x1-x0); + + assert(weight != 0); + + //clip to the input region + if(x0 >= s.get_w() || x1 <= 0) return acum; + if(y0 >= s.get_h() || y1 <= 0) return acum; + + if(x0 < 0) { x0 = 0; xib = 0; } + if(x1 >= s.get_w()) + { + x1 = s.get_w(); //want to be just below the last pixel... + xie = s.get_w()-1; + } + + if(y0 < 0) { y0 = 0; yib = 0; } + if(y1 >= s.get_h()) + { + y1 = s.get_h(); //want to be just below the last pixel... + yie = s.get_h()-1; + } + + float ylast = y0, xlastb = x0; + const_pen pen = s.get_pen(xib,yib); + + for(yi = yib; yi < yie; ylast = ++yi, pen.inc_y()) + { + const float yweight = yi+1 - ylast; + + float xlast = xlastb; + for(xi = xib; xi < xie; xlast = ++xi, pen.inc_x()) + { + const float w = yweight*(xi+1 - xlast); + acum += pen.get_value()*w; + } + + //post... with next being fractional... + const float w = yweight*(x1 - xlast); + acum += pen.get_value()*w; + + pen.dec_x(xie-xib); + } + + //post in y direction... must have all x... + { + const float yweight = y1 - ylast; + + float xlast = xlastb; + for(xi = xib; xi < xie; xlast = ++xi) + { + const float w = yweight*(xi+1 - xlast); + + acum += pen.get_value()*w; + } + + //post... with next being fractional... + const float w = yweight*(x1 - xlast); + acum += pen.get_value()*w; + } + + acum *= 1/weight; + return acum; + } }; _ETL_END_NAMESPACE ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ Synfig-devl mailing list Synfig-devl@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/synfig-devl