arbeit
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

TFRasterize.h

Go to the documentation of this file.
00001 //------------------------------------------------------------------------
00002 //
00003 //   Joe Kniss
00004 //     3-20-03
00005 //                   ________    ____   ___ 
00006 //                  |        \  /    | /  /
00007 //                  +---+     \/     |/  /
00008 //                  +--+|  |\    /|     < 
00009 //                  |  ||  | \  / |  |\  \ 
00010 //                  |      |  \/  |  | \  \ 
00011 //                   \_____|      |__|  \__\
00012 //                       Copyright  2003 
00013 //                      Joe Michael Kniss
00014 //                   <<< jmk@cs.utah.edu >>>
00015 //               "All Your Base are Belong to Us"
00016 //-------------------------------------------------------------------------
00017 
00018 /// TFRasterize.h
00019 
00020 #ifndef __SIMIAN_TF_RASTERIZE_DOT_H
00021 #define __SIMIAN_TF_RASTERIZE_DOT_H
00022 
00023 #include <mathGutz.h>
00024 #include <iostream>
00025 
00026 using namespace std; /// bad
00027 
00028 /// a triangle class if you don't already have somthing
00029 /// to represent a triangle
00030 
00031 template<class T>
00032 class Triangle {
00033 public:
00034    typedef gutz::vec3<T> Vec3;
00035    enum N_TEX_COORDS {
00036       N_TEX = 8
00037    };
00038 
00039    Triangle()
00040    {
00041       for(int i=0; i<3; ++i)
00042          pts[i] = 0;
00043       for(int i=0; i<N_TEX; ++i)
00044          for(int j=0; j<3; ++j)
00045             tex[i][j] = 0;
00046    }
00047 
00048    Triangle(Vec3 *p1, Vec3 *p2, Vec3 *p3)
00049    {
00050       if((!pi) || (!p2) || (!p3))
00051       {
00052          std::cerr << "Triangle(), got null point!" << std::endl;
00053       }
00054       pts[0] = p1; pts[1] = p2; pts[2] = p3;
00055       for(int i=0; i<N_TEX; ++i)
00056          for(int j=0; j<3; ++j)
00057             tex[i][j] = 0;
00058    }
00059    Triangle(const Triangle &t)
00060    {
00061       for(int i=0; i<3; ++i) pts[i] = t.pts[i];
00062       for(int i=0; i<N_TEX; ++i)
00063          for(int j=0; j<3; ++j)
00064             tex[i][j] = t.tex[i][j];
00065    }
00066    ///~Triangle();  /// just using default for now
00067    Triangle &operator=(const Triangle &t)
00068    {
00069       for(int i=0; i<3; ++i) pts[i] = t.pts[i];
00070       for(int i=0; i<N_TEX; ++i)
00071          for(int j=0; j<3; ++j)
00072             tex[i][j] = t.tex[i][j];
00073       return *this;
00074    }
00075    void setPoints(Vec3 *p1, Vec3 *p2, Vec3 *p3)
00076    {
00077       if((!p1) || (!p2) || (!p3))
00078       {
00079          std::cerr << "Triangle(), got null point!" << std::endl;
00080       }
00081       pts[0] = p1; pts[1] = p2; pts[2] = p3;
00082    }
00083    void setTexCoord(int tc, Vec3 *t1, Vec3 *t2, Vec3 *t3)
00084    {
00085       if((!t1) || (!t2) || (!t3))
00086       {
00087          std::cerr << "Triangle(), got null tc!" << std::endl;
00088       }
00089       tex[tc][0] = t1; tex[tc][1] = t2; tex[tc][2] = t3;
00090    }
00091 
00092    Vec3 &getTex(int tcNum, int ptNum)             { return *(tex[tcNum][ptNum]); }
00093    const Vec3 &getTex(int tcNum, int ptNum) const { return *(tex[tcNum][ptNum]); }
00094 
00095    /// a convenient accessor!
00096    Vec3       &operator[](int i)       { return *(pts[i]); }
00097    const Vec3 &operator[](int i) const { return *(pts[i]); }
00098 
00099    /// three points, verticies of triangle
00100    Vec3  *pts[3];
00101    /// N_TEX coordinate sets, one Vec3 coordinate for each point
00102    Vec3  *tex[N_TEX][3];
00103 };
00104 
00105 
00106 /// TriRasterInfo:
00107 ///   a class to help you setup rasterization.
00108 ///  Works kind of like an iterator, here is an example:
00109 /// \code
00110 ///  TriRasterInfo ri(imageSizeX, imageSizeY);
00111 ///  for(...)/// for each triangle
00112 ///  {  
00113 ///     ri.setTri(someTriangle);
00114 ///     while(!ri.end())
00115 ///     {
00116 ///         /// position of fragment is ri.x() and ri.y()
00117 ///         /// you can interpolate values using the interp*() functions
00118 ///         ++ri;  /// increment to the next pixel
00119 ///     }
00120 ///  }
00121 /// \endcode
00122 ///
00123 /// any structure that returns a point using "[]" will 
00124 /// work as the triangle type, you could just use an 
00125 /// array of vec3<>'s.
00126 ///   TODO: make this work for c arrays of c arrays??
00127 template< class T, class TT = Triangle<T> >
00128 class TriRasterInfo {
00129 public:
00130    typedef gutz::vec4<T> Vec4;
00131    typedef gutz::vec3<T> Vec3;
00132    typedef gutz::vec2<T> Vec2;
00133    typedef gutz::ray3<T> Ray3;
00134    typedef TT   Tri3;
00135 
00136    TriRasterInfo(int sx, int sy) : yPos(0), maxY(0), _sx(sx), _sy(sy) {}
00137 
00138    inline int  getSizeX() const { return _sx; }
00139    inline int  getSizeY() const { return _sy; }
00140 
00141    /// uncomment this if there are issues with non virtual 
00142    /// destructors
00143    ///~TriRasterInfo() {}
00144 
00145    /// use it like an iterator!... kind of
00146    inline bool end() const { return yPos >= maxY; }
00147 
00148    inline TriRasterInfo &operator++() 
00149    {
00150       incX();
00151       if(xPos >= maxX)
00152       {
00153          //cerr << " scan line y = " << yPos << " : xmin, xmax => " << minX << " "  << maxX << endl;
00154          incY();
00155       }
00156       return *this;
00157    }
00158 
00159    /// returns true if the triangle has NO renderable pixels
00160    /// returns false if the has any renderable pixels
00161    inline bool        setTri(Tri3 const *t) { return setUp(t); }
00162    inline Tri3 const *getTri() const { return tri; }
00163 
00164    inline T x() const { return xPos; }
00165    inline T y() const { return yPos; }
00166    
00167    inline void reset() { setUp(this->tri); }
00168 
00169    ///////////////////////////////////////////////////////////
00170    /// get the minimum x for the CURRENT scan line (at y())
00171    int   getMinX() const { return minX; }
00172    /// get the starting scan line (min y pos)
00173    int   getMinY() const { return minY; }
00174 
00175    ///////////////////////////////////////////////////////////
00176    /// get the maximum x for the CURRENT scan line (at y())
00177    int   getMaxX() const { return maxX; }
00178    /// get the ending scan line (max y pos)
00179    int   getMaxY() const { return maxY; }
00180 
00181    ///////////////////////////////////////////////////////////
00182    /// get the max x position in image for some scan line yp
00183    inline int getMaxX(T yp) const
00184    {
00185       if(yPos > yswapEnd) /// lower segment
00186       {
00187          const T t = intersectY(yPos, r[2]);
00188          return clamp(0, int(t)-1, _sx-1);
00189       }
00190       else  /// upper segment
00191       {
00192          const T t = intersectY(yPos, r[ee]);
00193          return clamp(0, int(t)-1, _sx-1);
00194       }
00195    }
00196 
00197    ///////////////////////////////////////////////////////////
00198    /// get the min x position in image for some scanline yp
00199    inline int getMinX(T yp) const 
00200    {
00201       if(yPos > yswapStart)
00202       {
00203          const T t = intersectY(yPos, r[2]);
00204          return clamp(0, int(t), _sx-1);
00205       }
00206       else
00207       {
00208          T t = intersectY(yPos, r[se]);
00209          return clamp(0, int(t), _sx-1);
00210       }
00211    }
00212 
00213 
00214    /// increment y
00215    inline void incY() 
00216    {
00217       ++yPos;
00218       minX = getMinX(yPos);
00219       xPos = T(minX);
00220       maxX = getMaxX(yPos);
00221       setBary(T(xPos), T(yPos));
00222    }
00223 
00224    /// increment x
00225    inline void incX()
00226    {
00227       alpha += xa;
00228       beta  += xb;
00229       gamma += xg;
00230       ++xPos;
00231    }
00232 
00233    inline T getAlpha(const T x, const T y) const
00234    { return x * xa + y * ya + ac; }
00235 
00236    inline T getBeta(const T x, const T y) const
00237    { return x * xb + y * yb + bc; }
00238 
00239    inline T getGamma(const T x, const T y) const
00240    { return x * xg + y * yg + gc; }
00241 
00242    ////////////////////////////
00243    /// update barycentric coordinates for the current x(),y() positions
00244    /// alpha, beta, gamma will be set based on
00245    ///   x,y pos you give
00246    ////////////////////////////
00247    inline void setBary(const T x, const T y)
00248    {
00249       alpha = getAlpha(x,y);
00250       beta  = getBeta(x,y);
00251       gamma = getGamma(x,y);
00252    }
00253    /// quick check if current pos (x(),y()) is inside triangle
00254    inline bool validBary() const
00255    {
00256       return (alpha >= 0) && (beta >= 0) && (gamma >= 0);
00257    }
00258 
00259    /// interpolation on a triangle using barycentric coordinates
00260    
00261    /// interpolate a 4 vector using the current barycentric coordinates
00262    template< class VT > //< any vector type even a c array
00263    inline Vec4 interp4(const VT &v0, const VT &v1, const VT &v3) const
00264    {
00265       return Vec4(v0[0] * alpha + v1[0] * beta + v2[0] * gamma,
00266                   v0[1] * alpha + v2[1] * beta + v2[1] * gamma,
00267                   v0[2] * alpha + v2[2] * beta + v2[3] * gamma,
00268                   v0[3] * alpha + v2[3] * beta + v2[3] * gamma);
00269    }
00270    /// interpolate a 3 vector using the current barycentric coordinates
00271    template< class VT > //< any vector type even a c array
00272    inline Vec3 interp3(const VT &v0, const VT &v1, const VT &v2) const
00273    {
00274       return Vec3(v0[0] * alpha + v1[0] * beta + v2[0] * gamma,
00275                   v0[1] * alpha + v2[1] * beta + v2[1] * gamma,
00276                   v0[2] * alpha + v2[2] * beta + v2[3] * gamma);
00277    }
00278    /// interpolate a 2 vector using the current barycentric coordinates
00279    template< class VT > //< any vector type even a c array
00280    inline Vec2 interp2(const VT &v0, const VT &v1, const VT &v2) const
00281    {
00282       return Vec3(v0[0] * alpha + v1[0] * beta + v2[0] * gamma,
00283                   v0[1] * alpha + v2[1] * beta + v2[1] * gamma);
00284    }
00285    /// interpolate a scalar using the current barycentric coordinates
00286    template< class TP > ///< any type
00287    inline TP interp(const TP &v0, const TP &v1, const TP &v2) const
00288    {
00289       return v0 * alpha + v1 * beta + v2 * gamma;
00290    }
00291 
00292 
00293 
00294 public: /// but NOT FOR GENERAL USE
00295 
00296    ////////////////////////////
00297    /// public data
00298    ////////////////////////////
00299    T    alpha,beta,gamma;
00300    T    yPos;  //< current Y position
00301    T    xPos;  //< current X position
00302    /// min/max values for setting up loops
00303    int  minY;
00304    int  maxY;
00305    int  minX;
00306    int  maxX;
00307    Tri3 const *tri;
00308 
00309    /////////////////////////////////////////////////////////////
00310    /// setup for rasterizaton, set the triangle being rasterized
00311    ///   NOT FOR GENERAL USE, use setTri()
00312    /////////////////////////////////////////////////////////////
00313    /// \code
00314    ///  2 basic cases for "tight rendering" 
00315    ///      case 1    case 2            Loose/"de-implemented"
00316    ///       p0=sp    p0=sp             x---x
00317    ///     r0  o        o  r0           |o  |
00318    ///     se /| r1  r1 |\ ee           ||\ |
00319    ///  p1-> o | ee  se | o <- p1=mp    || o|
00320    ///     r2 \|        |/ r2           ||/ |
00321    ///     me  o        o  me           |o  |
00322    ///       p2=ep    p2=ep             x---x
00323    /// \endcode 
00324    ///   There is one additional check made to insure that the 
00325    ///     start and end edges are not horizontal, if they are we
00326    ///     swap immediately. If two are horizontal, we don't have
00327    ///     any pixels to be rendered.
00328    /// Users need not worry about this, it's just an explanation of
00329    ///  how this function sets things up.
00330    /////////////////////////////////////////////////////////////
00331    
00332    inline bool setUp(Tri3 const *t3)
00333    {
00334       /// set internal triangle
00335       this->tri = t3;
00336       /// alias Tri* to a Tri, for easier access
00337       const Tri3 &t = (*t3);
00338       //cerr << " rasterizing triangle 0 = " << t[0] << "  1= " << t[1] << "  2= " << t[2] << endl;
00339       /// which of the triangle points is smallest in Y (by index)
00340       int sp = mini3(t[0].y, t[1].y, t[2].y);
00341       int ep = maxi3(t[0].y, t[1].y, t[2].y); //< largest y (by index)
00342       int mp = 0; //< middle y (by index)
00343       if(((0==sp) && (2==ep)) || ((2==sp) && (0==ep))) mp = 1;
00344       if(((1==sp) && (0==ep)) || ((0==sp) && (1==ep))) mp = 2;
00345       //cerr << " order " << sp << " " << mp << " " << ep << endl;
00346       /// Init bounding box ( and starting point for loose ) (by integer value)
00347       minY = clamp(0,int(min3(t[0].y, t[1].y, t[2].y)), _sy-1);
00348       maxY = clamp(0,int(max3(t[0].y, t[1].y, t[2].y))-1, _sy-1);
00349       /// need to capture this to see if we have any usefull pixels
00350       int tminX = clamp(0,int(min3(t[0].x, t[1].x, t[2].x)), _sx-1);
00351       int tmaxX = clamp(0,int(max3(t[0].x, t[1].x, t[2].x))-1, _sx-1);
00352       /// starting Y position, first scan line
00353       yPos = T(minY);
00354       /// build rays for tight rendering.
00355       ///  rays always point in +y direction
00356       ///  these correspond to case 1 above
00357       r[0] = Ray3(t[sp], t[mp] - t[sp]);
00358       r[1] = Ray3(t[sp], t[ep] - t[sp]);
00359       r[2] = Ray3(t[mp], t[ep] - t[mp]);
00360       /// which case are we in for "tight" rendering
00361       //cerr << " swaps " << t[sp].y << " " << t[mp].y << " " << t[ep].y << endl;
00362       yswapStart = T( int(t[mp].y) );   /// case 1
00363       yswapEnd   = T( maxY );  
00364       se = 0;
00365       ee = 1;
00366       if(r[se].d.y == 0)  /// start edge is horizontal
00367       {
00368          se = 2;
00369       }
00370       if(r[ee].d.y == 0)  /// end edge is horizontal
00371       {
00372          ee = 2;
00373       }
00374       /// init the tmp ray, only the .p.y value will be modified...
00375       /// should ride the x=0 axis, point toward (1,0,0)
00376       ///tmpr = Ray3(Vec3(T(0.0),r[se].p.y + r[se].d.y/T(2.0),T(0.0)), Vec3(T(1.0), T(0.0), T(0.0)));
00377       //cerr << " edge start " << r[se].p << "     " << r[se].d << endl;
00378       //cerr << " edge next  " << r[ee].p << "     " << r[ee].d << endl;
00379       //cerr << " edge swap  " << r[2].p << "     " << r[2].d << endl;
00380       //cerr << endl;
00381       //cerr << " tmp ray " << tmpr.p << "  =  " << tmpr.d << endl;
00382       //cerr << " intersect " << intersect2D(tmpr,r[se]) << "   " << intersect2D(tmpr,r[ee]) << endl;
00383       T typ = r[se].p.y + r[se].d.y/T(2.0);
00384       if(intersectY(typ,r[se]) > intersectY(typ,r[ee])) /// case 2
00385       {
00386          //cerr << " swaping edge order " << endl;
00387          int tmp = se;
00388          se = ee;
00389          ee = tmp;
00390          yswapStart = T( maxY );
00391          yswapEnd   = T( int(t[mp].y) );
00392       }
00393       /// now that we have edge orders figured out... 
00394       /// set the current x position
00395       minX = int(clamp(0,intersectY(yPos,r[se]),_sx-1));
00396       xPos = T(minX);
00397       maxX = int(clamp(0,intersectY(yPos,r[ee])-1,_sx-1));
00398       //cerr << " edge start " << r[se].p << "     " << r[se].d << endl;
00399       //cerr << " edge next  " << r[ee].p << "     " << r[ee].d << endl;
00400       //cerr << " edge swap  " << r[2].p << "     " << r[2].d << endl;
00401       //cerr << " yswapS = " << yswapStart << endl;
00402       //cerr << " yswapE = " << yswapEnd << endl;
00403 
00404       //cerr << " xdims " << minX << "  " << maxX << endl;
00405       //cerr << " ydims " << minY << "  " << maxY << endl;
00406       /// precompute barycentric constants
00407       setupBary(t[0],t[1],t[2]);
00408       /// initialize them
00409       setBary(T(xPos),T(yPos));
00410       /// report if there are any pixels that need to be rendered
00411       return !(minY < maxY) || !(tminX < tmaxX);
00412    }
00413 
00414    /// shouldn't create without a size!!!
00415    TriRasterInfo() : yPos(0), maxY(0), _sx(0), _sy(0) {}
00416 
00417    inline T intersectY(const T yp, const Ray3 &r) const
00418    {
00419       /// since gutz::intersect2D() is more general than 
00420       /// we need for this algorithm, I optimized it by 
00421       /// removing terms that will always be zero. And assume that
00422       /// we don't need to check for divide by zero
00423       /// r1: p = (0,yp), d=(1,0)
00424       /// [d1x, d1y] dot Perp([d2x,d2y])
00425       ///const T div = -r.d.y; /// removed check for x/0
00426       ///if(!div) return std::numeric_limits<T>::infinity();
00427       return r.p.x + (r.p.y * r.d.x - yp*r.d.x)/(-r.d.y);
00428    }
00429 
00430    inline 
00431    T intersect2D(const Ray3 &ri, const Ray3 &ro) const
00432    {
00433       return gutz::intersect2D(ri.p.x, ri.p.y, ri.d.x, ri.d.y,
00434                                ro.p.x, ro.p.y, ro.d.x, ro.d.y);
00435    }
00436 
00437    /// image size:
00438    int _sx, _sy;
00439 
00440    /// pre-computed alpha, beta, gamma constants:
00441    /// ex: alpha = x * xa + y * ya + ca
00442    T xa, ya, ac, xb, yb, bc, xg, yg, gc;
00443    void setupBary(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2)
00444    {
00445       /// alpha
00446       xa = p1.y - p2.y;
00447       ya = p2.x - p1.x;
00448       ac  = p1.x * p2.y - p2.x * p1.y;
00449       /// beta
00450       xb = p2.y - p0.y;
00451       yb = p0.x - p2.x;
00452       bc  = p2.x * p0.y - p0.x * p2.y;
00453       /// gamma
00454       xg = p0.y - p1.y;
00455       yg = p1.x - p0.x;
00456       gc  = p0.x * p1.y - p1.x * p0.y;
00457       /// take care of divide
00458       /// alpha
00459       T tmp;
00460       tmp = T(1.0)/(p0.x * xa + p0.y * ya + ac);
00461       xa *= tmp; ya *= tmp; ac *= tmp;
00462       tmp = T(1.0)/(p1.x * xb + p1.y * yb + bc);
00463       xb *= tmp; yb *= tmp; bc *= tmp;
00464       tmp = T(1.0)/(p2.x * xg + p2.y * yg + gc);
00465       xg *= tmp; yg *= tmp; gc *= tmp;
00466    }
00467 
00468    int  se, ee;
00469    T  yswapStart, yswapEnd;
00470 
00471    Ray3 r[3];
00472 
00473 };
00474 
00475 #if 0
00476 class TFRasterInfo : public TriRasterInfo<STF::tfSType, Triangle<STF::tfSType> >
00477 {
00478 public:
00479    typedef STF::tfSType      SType;
00480    typedef Triangle<SType>   TriType;
00481    typedef gutz::vec2<SType> Vec2;
00482    typedef gutz::mat3<SType> Mat3;
00483 
00484    TFRasterInfo() : TriRasterInfo<SType,TriType>() {}
00485    TFRasterInfo(const TriType &t) : TriRasterInfo<SType,TriType>(t) {}
00486    TFRasterInfo(const TriType t)  : TriRasterInfo<SType,TriType>(t) {}
00487 
00488    ~TFRasterInfo();
00489 
00490    /// optimize rasterization by leverating these to
00491    /// speed up transformations from map space to 
00492    ///  tf-element space
00493    SType xIncS;
00494    SType yIncS;
00495    Vec2  xIncV;
00496    Vec2  yIncV;
00497    Mat3  xform;
00498 
00499 
00500 };
00501 #endif
00502 
00503 
00504 #endif
00505 
00506 
00507 
00508 
00509 #if 0
00510 
00511 
00512 #include <limits>
00513 #include "TFParams.h"
00514 #include <iostream>
00515 
00516 namespace STFR { /// namespaced to prevent pollution (give a hoot?)
00517 
00518 typedef STF::tfSType      ST;
00519 typedef STF::tfRangeType  VT;
00520 typedef STF::tfDomainType PT;
00521 typedef STF::tfVec2       V2;
00522 
00523 /// a generic rasterization algorithm.
00524 ///
00525 /// This is super nasty! But it is so for several reasons... 
00526 /// A.
00527 ///   We need to be able to play with blend ops since:
00528 ///     1) they are different for each optical property
00529 ///     2) there are multiple ways to blend TFElements and 
00530 ///        I don't know which one is right
00531 /// B.
00532 ///   We also need to be able to generate a 2D TF image from any 
00533 ///     combination of 4 optical properties. I choose 4 since it 
00534 ///     is the universial type of images & textures
00535 ///
00536 /// C.
00537 ///   I don't, and you shouldn't, want to write thousands of 
00538 ///     rasterization algorithms; one for each Element type, 
00539 ///     and one for each combination of values...
00540 ///
00541 /// D.
00542 ///   We need this to go very very fast.
00543 ///
00544 /// This is at least my third iteration on a generic method for rasterizing elements.
00545 /// The first iterations used virtual functions for eval and blend, they went very slow.
00546 ///  Unaceptably slow!  We need to avoid virtual function calls in the main loop if we
00547 ///  can help it!  I had to sacrifice generality in blending, we must select the blendops
00548 ///  at compile time, but they can now be inlined.   This is the primary reason why this
00549 ///  algorithm isn't general with respect to the number of optical properties rasterized.
00550 /// There is a helper dispatch #def below, it should be used by a subclass of 
00551 ///  TFElement.  It is preferiable that the eval() function be inlined, but it is 
00552 ///  absolutely nessesary that it NOT be virtual, that will make rasterization very slow.
00553 
00554 template<
00555    class B1,  ///blenders
00556    class B2,
00557    class B3,
00558    class B4,
00559    class NT,   ///nrro type 
00560    class EL    ///element type
00561 >   ///blend type
00562 inline
00563 void rasterize2D4(Nrro::NrroIter<NT> ni, 
00564                   const gutz::vec2i &posIdx, 
00565                   const STF::tfRangeIdx &valIdx,
00566                   const EL *elt)
00567 {
00568    std::cerr << " hi type = " << typeid(NT).name() << std::endl;
00569 
00570    vec2<NT> mmm; /// min & max for the map
00571 
00572    if(numeric_limits<NT>::epsilon()) /// float/double type
00573    {
00574       mmm = vec2<NT>(NT(0.0),NT(1.0));
00575    }
00576    else /// integral type
00577    {
00578       mmm = vec2<NT>(numeric_limits<NT>::min(), numeric_limits<NT>::max());
00579    }
00580 
00581    /// idicies 
00582    const int i1 = valIdx[0];
00583    const int i2 = valIdx[1];
00584    const int i3 = valIdx[2];
00585    const int i4 = valIdx[3];
00586 
00587    /// complete bounding box
00588    const PT bmin = elt->getMinBox();
00589    const PT bmax = elt->getMaxBox();
00590 
00591    /// bounding box for the current axies
00592    const int minX = clamp(0, int(bmin[posIdx.x] * ni->dim(1)), ni->dim(1));
00593    const int minY = clamp(0, int(bmin[posIdx.y] * ni->dim(2)), ni->dim(2));
00594    const int maxX = clamp(0, int(bmax[posIdx.x] * ni->dim(1)), ni->dim(1));
00595    const int maxY = clamp(0, int(bmax[posIdx.y] * ni->dim(2)), ni->dim(2));
00596 
00597    /// tf domain positions and deltas for rasterization
00598    const ST px = minX/float(ni->dim(1));
00599    const ST py = minY/float(ni->dim(2));
00600    const ST dx = 1.0f/float(ni->dim(1));
00601    const ST dy = 1.0f/float(ni->dim(2));
00602 
00603    /// temps used in inner loop, so we are not constructing tons of stuff
00604    ST u;
00605    VT o;
00606    V2 pos(px,py);
00607 
00608    /// Rasterize!!!
00609    for(int y = minY; y<= maxY; ++y, pos.y+=dy)  /// y axis
00610    {
00611       for(int x = minX; x<= maxX; ++x, pos.x+=dx) /// x axis
00612       {
00613          /// over values (values from this element)
00614          o = elt->eval(pos, posIdx);
00615 #if 1
00616          /// update the map
00617 
00618          u = g_affine(NT(mmm.x), ni(0,x,y), NT(mmm.y), ST(0.0), ST(1.0));
00619          //B1::blend(o,u,i1);
00620          ni(0,x,y) = g_affine(ST(0.0), o[i1], ST(1.0), NT(mmm.x), NT(mmm.y));
00621 
00622          u = g_affine(NT(mmm.x), ni(1,x,y), NT(mmm.y), ST(0.0), ST(1.0));
00623          //B2::blend(o,u,i2);
00624          ni(1,x,y) = g_affine(ST(0.0), o[i2], ST(1.0), NT(mmm.x), NT(mmm.y));
00625 
00626          u = g_affine(NT(mmm.x), ni(2,x,y), NT(mmm.y), ST(0.0), ST(1.0));
00627          //B3::blend(o,u,i3);
00628          ni(2,x,y) = g_affine(ST(0.0), o[i3], ST(1.0), NT(mmm.x), NT(mmm.y));
00629 
00630          u = g_affine(NT(mmm.x), ni(3,x,y), NT(mmm.y), ST(0.0), ST(1.0));
00631          //B4::blend(o,u,i4);
00632          ni(3,x,y) = g_affine(ST(0.0), o[i4], ST(1.0), NT(mmm.x), NT(mmm.y));
00633 
00634 #endif
00635       }
00636       pos.x = px;
00637    }
00638 
00639 }
00640 
00641 /////////////////// Pure nasty! /////////////////////
00642 /// copied and modified from nrroDispatch.h
00643 
00644 #define dispatchRast2D4(B1,B2,B3,B4,NSP,PI,VI,EL) \
00645    \
00646    switch( NSP->getType() ) { \
00647    case Nrro::CHAR: \
00648       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<char>(), PI , VI , EL ); \
00649       break; \
00650    case Nrro::UCHAR:  \
00651       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<unsigned char>(), PI , VI , EL ); \
00652       break; \
00653    case Nrro::SHORT: \
00654       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<short>(), PI , VI , EL ); \
00655       break; \
00656    case Nrro::USHORT: \
00657       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<unsigned short>(), PI , VI , EL ); \
00658       break; \
00659    case Nrro::INT: \
00660       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<int>(), PI , VI , EL ); \
00661       break; \
00662    case Nrro::UINT: \
00663       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<unsigned int>(), PI , VI , EL ); \
00664       break; \
00665    case Nrro::FLOAT: \
00666       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<float>(), PI , VI , EL ); \
00667       break; \
00668    case Nrro::DOUBLE: \
00669       STFR::rasterize2D4< B1 , B2 , B3 , B4 >( NSP ->begin<double>(), PI , VI , EL ); \
00670       break; \
00671    }
00672 
00673 } /// end namespace STFR
00674 
00675 #endif
00676 
00677 

Send questions, comments, and bug reports to:
jmk