Main Page | File List

Canvas.h

Go to the documentation of this file.
00001 /**
00002  *\file         Canvas.h
00003  *
00004  *\brief        The Canvas class is a discrete simulation of the real life canvas. 
00005  *
00006  *              The canvas is cutted into grid structure, with <b><var>vReso</var></b> grids along
00007  *              vertical (<b><var>Row</var></b>) direction and <b><var>hReso</var></b> horizontal grids along 
00008  *              horizontal(<b><var>Col</var></b>) direction. Each rectangular grid is called a pixel, or picture
00009  *              element, and is specified by its lower-left <b><var>(row, col)</var></b> position. 
00010  *              The coordinate system has the lower-left corner of the canvas as its origin, 
00011  *              with <b><var>Row</var></b> going up and <b><var>Col</var></b> going right. The lower-left corner 
00012  *              pixel has a coordinate of <b><var>(0,0)</var></b>, and the upper-right one of <b><var>
00013  *              (hReso - 1, vReso - 1)</var></b>. 
00014  *
00015  *              A <b><var>(x, y)</var></b> pair means <b><var>col = x+hReso/2, and row = y+vReso/2</var></b>.
00016  *
00017  *              To each piexel <b><var>(row, col)</var></b> on the Canvas, a RGB color value is associated,
00018  *              which can be accessed via index operator [<b><var>row</var></b>][<b><var>col</var></b>].
00019  *
00020  *              WritePPM() writes the Canvas to an image file of PPM format.
00021  *
00022  * <H4>11 Jul 2004:</H4> Point structure and perspectiveProjection(Point const&) added. Now the Canvas is actually a virutal camera
00023  *              in the simplest setting: the Canvas plane is centered at z=0 with x-size of hReso, and y-size of vReso, 
00024  *              Eye at eye_at (>0) and looking along positive z direction.  eye_at defaults to hReso / 2.
00025  *
00026  *              Now the triangle primitives are updated so the given points are in 3D space. The other primitives are
00027  *              not updated though, and actually can be deleted from Canvas class, since for 3D graphics, everything 
00028  *              is usually tesselated by triangles.
00029  *
00030  *\author       Xianming Chen
00031  *
00032  */
00033 
00034 
00035 #ifndef _CANVAS_H_
00036 #define _CANVAS_H_
00037 
00038 #include "RGB.h"
00039 #include "xmath.h"
00040 #include "Point.h"
00041 #include "color.h"
00042 
00043 #include <string>
00044 #include <cassert>
00045 #include <set>
00046 
00047 using namespace std;
00048 
00049 namespace columbia
00050 {
00051   
00052   struct ScannedResult
00053   {
00054       ScannedResult(int X, int Y, float Z, RGB const& Col) : x(X), y(Y), z(Z), col(Col) { }
00055       bool operator<(ScannedResult const& rhs) const { return (y<rhs.y) || ( (y==rhs.y) && (x<rhs.x) ); }
00056       int x, y;
00057       float z;
00058       RGB col;
00059   };
00060   
00061   class Canvas
00062   { 
00063   public:
00064       explicit Canvas(int resoH = 512, int resoV = 512) : hReso(resoH), vReso(resoV), filename("tmp.ppm"), data(0), z_buffer(0)  { init(); }
00065       ~Canvas() { delete [] data; delete [] z_buffer; }
00066 
00067       void Clear(RGB const&);
00068       
00069       RGB* operator[] (int r)                    { assert(r>=0 && r<vReso); return data + r*hReso; }
00070       RGB& Pixel(int row, int col);              //! Use this instead of the [] operator if both row and col number checking is needed.
00071       float& Z(int row, int col);    
00072 
00073       /**
00074        * Scan-convert a line segment given two end points. The scan conversion stop right before the second end point.
00075        * If output = 0, Draw a line segment between two end points, (x1,y1) and (x2,y2).  Each pixel color is interpolated from two end colors.
00076        * Else only return scanned result to output.
00077        *
00078        * Also interpolate between given z-valus, and write to canvas only after passing z-buffer algorithm.
00079        */
00080       void ScanLineSegment(int x1, int y1, float z1, RGB const& col1, int x2, int y2, float z2, RGB const& col2, set<ScannedResult>* output=0);
00081       
00082 
00083       void WireTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3);
00084       void SolidTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3);
00085       
00086       void WritePPM(const char* = 0) const;
00087 
00088       int hReso, vReso;                          //! Resolutions (pixel #)at horizontal and vertical directions.
00089       std::string filename;                      //! write as PPM image file name.
00090 
00091 
00092   private:
00093       RGB* data;
00094       float* z_buffer;                           // z-buffer value.
00095       
00096       bool swap_xy, flip_y;                      // swap x&y if abs(slope) > 1.0, flip y if y<0.
00097 
00098       void init();
00099 
00100       void scanLineSegment(int x1, int y1, float z1, RGB const& col1, int x2, int y2, float z2, RGB const& col2, set<ScannedResult>* output=0);
00101       
00102       void writePixel(int X, int Y, float cur_z, RGB const& col, set<ScannedResult>* output); 
00103 
00104       double eye_at;
00105       Point perspectiveProjection(Point const&); 
00106   };
00107   
00108   inline void Canvas :: writePixel(int X, int Y, float cur_z, RGB const& col, set<ScannedResult>* output)
00109   {
00110     if(swap_xy) swap(X,Y);
00111     if(flip_y)  Y = -Y; 
00112 
00113     if(output)
00114     {
00115       output->insert( ScannedResult(X, Y, cur_z, col) );
00116     }
00117     else if( (X >= -hReso/2 && X < hReso/2) &&
00118              (Y >= -vReso/2 && Y < vReso/2) )
00119     {
00120       if( cur_z > Z(Y + vReso/2, X + hReso/2) )
00121       {
00122         if(col == Red)
00123         {
00124 //        cout << "old z " << Z(Y + vReso/2, X + hReso/2) << endl;
00125 //        cout << "cur z " << cur_z << endl;
00126 //        cout << "old color " << Pixel(Y + vReso/2, X + hReso/2) << " replaced\n";
00127         }
00128 
00129         Z(Y + vReso/2, X + hReso/2) = cur_z;
00130         Pixel(Y + vReso/2, X + hReso/2) = col;
00131       }
00132       else if(col == Red)
00133       {
00134 //      cout << "old z " << Z(Y + vReso/2, X + hReso/2) << endl;
00135 //      cout << "cur z " << cur_z << endl;
00136 //      cout << "old color " << Pixel(Y + vReso/2, X + hReso/2) << " no replaced\n";
00137       }
00138       
00139     }
00140   }
00141   
00142 
00143   inline RGB& Canvas :: Pixel(int row, int col)
00144   {
00145     if(row >= vReso) { cout << "row = " << row << endl; throw "row number overflow\n"; }    
00146     if(row < 0)      { cout << "1row = " << row << endl; throw "row number underflow\n"; }
00147     if(col >= hReso) { cout << "col = " << col << endl; throw "col number overrflow\n"; }
00148     if(col < 0)      { cout << "col = " << col << endl; throw "col number underflow\n"; }
00149     return *(data + row * hReso + col);
00150   }
00151   
00152   inline float& Canvas :: Z(int row, int col)
00153   {
00154     if(row >= vReso) { cout << "row = " << row << endl; throw "row number overflow\n"; }    
00155     if(row < 0)      { cout << "1row = " << row << endl; throw "row number underflow\n"; }
00156     if(col >= hReso) { cout << "col = " << col << endl; throw "col number overrflow\n"; }
00157     if(col < 0)      { cout << "col = " << col << endl; throw "col number underflow\n"; }
00158     return *(z_buffer + row * hReso + col);
00159   }
00160 
00161   inline Point Canvas :: perspectiveProjection(Point const& P)
00162   {
00163     double scale = eye_at / (eye_at - P.z);
00164     return Point(P.x * scale, P.y * scale, P.z);
00165   }
00166 
00167 
00168 }
00169 
00170 #endif

Generated on Wed Jul 14 19:41:55 2004 by doxygen 1.3.6