Main Page | File List

Canvas.cpp

00001 #include "Canvas.h"
00002 #include "color.h"
00003 #include "xmath.h"
00004 #include <iostream>
00005 #include <fstream>
00006 #include <vector>
00007 
00008 
00009 using namespace std;
00010 
00011 namespace columbia
00012 {
00013 
00014   void Canvas :: init() 
00015   { 
00016     int N = hReso*vReso;
00017     
00018     delete [] data; 
00019     data = new RGB [N]; 
00020     memset(data, 0, sizeof(RGB) * N);
00021 
00022     delete [] z_buffer; 
00023     z_buffer = new float [N];
00024     fill(z_buffer, z_buffer+N, -1.0E9);
00025 
00026     eye_at = hReso / 2;     // default horizontal field of view = 90.
00027   }
00028   
00029   void Canvas :: Clear(RGB const& color)
00030   {
00031     for (int row = 0; row < vReso; row++) 
00032       for (int col = 0; col < hReso; col++) 
00033       {
00034         (*this)[row][col] = color;
00035       }
00036   }
00037   
00038   void Canvas :: Checkerboard(int sz, RGB col1, RGB col2)
00039   {
00040     for(int row = 0; row < vReso; row++)
00041       for(int col = 0; col < hReso; col++)
00042       {
00043         (*this)[row][col] = (col/sz + row/sz) % 2 ? col1 : col2;
00044       }
00045   }
00046 
00047 
00048 
00049   void Canvas :: WritePPM(const char *_filename) const
00050   {
00051     Canvas* This =  (Canvas*)this;
00052     
00053     if(!_filename) 
00054       _filename = filename.c_str();
00055 
00056     ofstream file;
00057     file.open (_filename, ios::out | ios::binary);
00058     
00059     if(file) 
00060     {
00061       file << "P6\n";   // color rawbits format
00062       file << hReso << " " << vReso << endl << 100 << endl;
00063   
00064       unsigned char r, g, b;
00065       for (int row = vReso-1; row >= 0; row--) 
00066         for (int col = 0; col < hReso; col++) 
00067         {
00068           r = (unsigned char) (100.0*(*This)[row][col][0]);  
00069           g = (unsigned char) (100.0*(*This)[row][col][1]);  
00070           b = (unsigned char) (100.0*(*This)[row][col][2]);  
00071 
00072           if(row==vReso-1 && col==0)
00073             r = (unsigned char)77, g = (unsigned char)78, b = (unsigned char)79;
00074           
00075           if(r>100.0 || g>100.0 || b>100.0)  throw "RGB color overflow\n"; 
00076 
00077           file << r << g << b;
00078         }
00079 
00080       file << endl;
00081       file.close();
00082     }
00083     else 
00084       cerr << "Can't open output file " << _filename << endl;
00085   }
00086   
00087 
00088   void Canvas :: ReadPPM(const char * _filename)
00089   {
00090     if(!_filename) 
00091       _filename = filename.c_str();
00092 
00093     ifstream file;
00094     file.open (_filename, ios::in | ios::binary);
00095     
00096     if(file) 
00097     {
00098       string id;
00099       file >> id;
00100       if(id != "P6") throw "not P6 ppm format\n";   // color rawbits format
00101 
00102       float scale;
00103       file >> hReso >> vReso >> scale;
00104       init();
00105       unsigned char r, g, b;
00106       file >> noskipws >> r;
00107       
00108       for (int row = vReso-1; row >= 0; row--) 
00109       {
00110         for (int col = 0; col < hReso; col++) 
00111         {
00112           file >> noskipws >> r >> noskipws >> g >> noskipws >> b;
00113           if(row==vReso-1 && col==0)
00114             cout << int(r) << "___ " << int(g) << "___ " << int(b) << endl;
00115 
00116           (*this)[row][col][0] = r / scale;  
00117           (*this)[row][col][1] = g / scale;  
00118           (*this)[row][col][2] = b / scale;  
00119         }
00120       }
00121       
00122       file.close();
00123     }
00124     else 
00125       cerr << "Can't open input file " << _filename << endl;
00126   }
00127 
00128 
00129 
00130   void Canvas :: _scanLineSegment(int x1, int y1, float z1, Point const* tex1, RGB const* col1, 
00131                                   int x2, int y2, float z2, Point const* tex2, RGB const* col2, 
00132                                   set<ScannedResult>* output)
00133   {
00134     assert( x2-x1 >= 1 && x2-x1 >= y2-y1 && y2-y1 >= 0);
00135 
00136     bool 
00137       has_tex = tex1 && tex2, 
00138       has_col = col1 && col2,
00139       horizontal =  y1==y2,
00140       diagonal = y2-y1==x2-x1;
00141 
00142     float scale = 1.0 / (x2 - x1);
00143 
00144     Point tex, tex_step; 
00145     if(has_tex)
00146     {
00147       tex = *tex1;
00148       tex_step = (*tex2 - *tex1) / (x2-x1);
00149     }
00150     
00151     RGB col, col_step;
00152     if(has_col)
00153     {
00154       col = *col1;
00155       col_step = (*col2 - *col1) * scale;
00156     }
00157     
00158     int y = y1; 
00159     float yy = y1, y_step = (y2 - y1) * scale;
00160     float z = z1,  z_step = (z2 - z1) * scale;
00161     
00162     for(int x = x1; x <= x2; ++x, z += z_step)
00163     {
00164       writePixel(x, y, z, has_tex? &tex : 0 , has_col? &col : 0, output);
00165 
00166       if(has_tex) tex += tex_step; 
00167       if(has_col) col += col_step; 
00168 
00169       if( ! horizontal )
00170         if( diagonal ) y++;
00171         else y = round( yy += y_step );
00172     }
00173   }
00174 
00175   void Canvas :: scanLineSegment(int x1, int y1, float z1, Point const* tex1, RGB const* col1, 
00176                                  int x2, int y2, float z2, Point const* tex2, RGB const* col2, 
00177                                  set<ScannedResult>* output)
00178   {
00179     if(x1==x2 && y1==y2) return;
00180 
00181     static RGB C1, C2;
00182     RGB *c1 = 0, *c2 = 0;
00183     if(col1 && col2)
00184     {
00185       C1 = *col1, C2 = *col2;
00186       c1 = &C1, c2 = &C2;
00187     }
00188 
00189     static Point T1, T2;
00190     Point *t1 = 0, *t2 = 0;
00191     if(tex1 && tex2)
00192     {
00193       T1 = *tex1, T2 = *tex2;
00194       t1 = &T1, t2 = &T2;
00195     }
00196 
00197     if(x1 > x2)                                       // always scan convert from left to right.
00198     {
00199       swap(x1, x2); swap(y1, y2); swap(z1, z2);
00200       if(c1 && c2) swap(*c1, *c2);
00201       if(t1 && t2) swap(*t1, *t2);
00202     }
00203     if( (flip_y = y1 > y2) )                          // always scan convert from down to up.
00204     {
00205       y1 = -y1, y2 = -y2;
00206     }
00207     if( (swap_xy = y2-y1 > x2-x1) )                   // and always scan convert a line with <= 45 deg to x-axis.
00208     {
00209       swap(x1, y1), swap(x2, y2);
00210     }
00211     _scanLineSegment(x1, y1, z1, t1, c1, x2, y2, z2, t2, c2, output);
00212   }
00213 
00214 
00215   void Canvas :: SolidTriangle(Point const& P1, Point const* T1, RGB const* col1, 
00216                                Point const& P2, Point const* T2, RGB const* col2, 
00217                                Point const& P3, Point const* T3, RGB const* col3)
00218                                
00219   {
00220     Point p1 = perspectiveProjection(P1);
00221     Point p2 = perspectiveProjection(P2);
00222     Point p3 = perspectiveProjection(P3);
00223 
00224     set<ScannedResult> scanned_pnts;                 // sorted in y val, and in x val if y val the same.
00225     scanLineSegment(round(p1.x), round(p1.y), p1.z, T1, col1, round(p2.x), round(p2.y), p2.z, T2, col2, &scanned_pnts);
00226     scanLineSegment(round(p1.x), round(p1.y), p1.z, T1, col1, round(p3.x), round(p3.y), p3.z, T3, col3, &scanned_pnts);
00227     scanLineSegment(round(p3.x), round(p3.y), p3.z, T3, col3, round(p2.x), round(p2.y), p2.z, T2, col2, &scanned_pnts);
00228     
00229     int cur_yval = vReso / 2 + 1;                    // initialize to an invalid value.
00230     set<ScannedResult> same_yval;                    // of the scanned result.
00231     
00232     bool 
00233       has_tex = T1 && T2 && T3, 
00234       has_col = col1 && col2 && col3;
00235     
00236     
00237     for (set<ScannedResult>::iterator it = scanned_pnts.begin(); it != scanned_pnts.end(); ++it)
00238     {
00239       int y = it->y;
00240       if(y != cur_yval) 
00241       {
00242         if(same_yval.size())
00243         {
00244           set<ScannedResult>::iterator it1 = same_yval.begin(), it2 = --same_yval.end();
00245           scanLineSegment(it1->x, cur_yval, it1->z, has_tex? &it1->tex : 0, has_col? &it1->col : 0, 
00246                           it2->x, cur_yval, it2->z, has_tex? &it2->tex : 0, has_col? &it2->col : 0);
00247           
00248           same_yval.clear();
00249         }
00250         cur_yval = y;
00251       }
00252       same_yval.insert(*it);
00253     }
00254   }
00255 }
00256 

Generated on Sun Jul 18 20:32:35 2004 by doxygen 1.3.6