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 
00039   void Canvas :: WritePPM(const char *_filename) const
00040   {
00041     Canvas* This =  (Canvas*)this;
00042     
00043     if(!_filename) 
00044       _filename = filename.c_str();
00045 
00046     ofstream file;
00047     file.open (_filename, ios::out | ios::binary);
00048     
00049     if(file) 
00050     {
00051       file << "P6\n";   // color rawbits format
00052       file << hReso << " " << vReso << endl << 100 << endl;
00053   
00054       unsigned char r, g, b;
00055       for (int row = 0; row < vReso; row++) 
00056         for (int col = 0; col < hReso; col++) 
00057         {
00058           r = (unsigned char) (100.0*(*This)[vReso-row-1][col][0]);  
00059           g = (unsigned char) (100.0*(*This)[vReso-row-1][col][1]);  
00060           b = (unsigned char) (100.0*(*This)[vReso-row-1][col][2]);  
00061 
00062           if(r>100.0 || g>100.0 || b>100.0)  throw "RGB color overflow\n"; 
00063 
00064           file << r << g << b;
00065         }
00066 
00067       file << endl;
00068       file.close();
00069     }
00070     else 
00071       cerr << "Can't open output file " << _filename << endl;
00072   }
00073 
00074 
00075 
00076   void Canvas :: scanLineSegment(int x1, int y1, float z1, RGB const& col1, int x2, int y2, float z2, RGB const& col2, set<ScannedResult>* output)
00077   {
00078     assert( x2-x1 >= 1 && x2-x1 >= y2-y1 && y2-y1 >= 0);
00079 
00080     if(y1 == y2)                                     // this is horizontal line, or vertical line if swap_xy set.
00081     {
00082       for(int x = x1; x <= x2; ++x)                   
00083       {
00084         double t = ( double(x-x1) ) / (x2 - x1);
00085         writePixel(x, y1, interpolate(t, z1, z2), interpolate(t, col1, col2), output);
00086       }
00087     }
00088     else if(y2-y1 == x2-x1)                         // diagonal lines.
00089     {
00090       int y = y1;
00091       for(int x = x1; x <= x2; ++x, ++y)
00092       {
00093         double t = ( double(x-x1) ) / (x2 - x1);
00094         writePixel(x, y, interpolate(t, z1, z2), interpolate(t, col1, col2), output);
00095       }
00096     }
00097     else     
00098     {
00099       for(int x = x1; x <= x2; ++x)
00100       {
00101         double t = ( double(x-x1) ) / (x2 - x1);
00102         writePixel(x, round( interpolate(t, double(y1), double(y2)) ), interpolate(t, z1, z2), interpolate(t, col1, col2), output);
00103       }
00104     }
00105   }
00106   
00107 
00108   void Canvas :: ScanLineSegment(int x1, int y1, float z1, RGB const& col1, int x2, int y2, float z2, RGB const& col2, set<ScannedResult>* output)
00109   {
00110     if(x1==x2 && y1==y2) return;
00111 
00112     RGB c1(col1), c2(col2);
00113     
00114     if(x1 > x2)                                       // always scan convert from left to right.
00115     {
00116       swap(x1, x2); swap(y1, y2); swap(z1, z2);
00117       swap(c1,  c2);
00118     }
00119     if( (flip_y = y1 > y2) )                          // always scan convert from down to up.
00120     {
00121       y1 = -y1, y2 = -y2;
00122     }
00123     if( (swap_xy = y2-y1 > x2-x1) )                   // and always scan convert a line with <= 45 deg to x-axis.
00124     {
00125       swap(x1, y1), swap(x2, y2);
00126     }
00127     scanLineSegment(x1, y1, z1, c1, x2, y2, z2, c2, output);
00128   }
00129 
00130 
00131   void Canvas :: WireTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3)
00132   {
00133     Point p1 = perspectiveProjection(P1);
00134     Point p2 = perspectiveProjection(P2);
00135     Point p3 = perspectiveProjection(P3);
00136     ScanLineSegment(round(p1.x), round(p1.y), p1.z, col1, round(p2.x), round(p2.y), p2.z, col2);
00137     ScanLineSegment(round(p1.x), round(p1.y), p1.z, col1, round(p3.x), round(p3.y), p2.z, col3);
00138     ScanLineSegment(round(p3.x), round(p3.y), p1.z, col3, round(p2.x), round(p2.y), p2.z, col2);
00139   }
00140   
00141   void Canvas :: SolidTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3)
00142   {
00143     Point p1 = perspectiveProjection(P1);
00144     Point p2 = perspectiveProjection(P2);
00145     Point p3 = perspectiveProjection(P3);
00146 
00147     set<ScannedResult> scanned_pnts;     // ele is <y, <x, col> >, sorted by y val.
00148 
00149     //    cout << "P1 P2 P3 "  << P1 << "\t\t" << P2 << "\t\t" << P3 << endl;
00150     
00151     //    cout << "scan line 12\n\n\n";
00152     ScanLineSegment(round(p1.x), round(p1.y), p1.z, col1, round(p2.x), round(p2.y), p2.z, col2, &scanned_pnts);
00153     //    cout << "scan line 13\n\n\n";
00154     ScanLineSegment(round(p1.x), round(p1.y), p1.z, col1, round(p3.x), round(p3.y), p3.z, col3, &scanned_pnts);
00155     //    cout << "scan line 32\n\n\n";
00156     ScanLineSegment(round(p3.x), round(p3.y), p3.z, col3, round(p2.x), round(p2.y), p2.z, col2, &scanned_pnts);
00157     
00158     int cur_yval = vReso / 2 + 1;                    // initialize to an invalid value.
00159     set<ScannedResult> same_yval;                    // of the scanned result.
00160     
00161     for (set<ScannedResult>::iterator it = scanned_pnts.begin(); it != scanned_pnts.end(); ++it)
00162     {
00163       int y = it->y;
00164       if(y != cur_yval) 
00165       {
00166         if(same_yval.size())
00167         {
00168           set<ScannedResult>::iterator it1 = same_yval.begin(), it2 = --same_yval.end();
00169           ScanLineSegment(it1->x, cur_yval, it1->z, it1->col,
00170                           it2->x, cur_yval, it2->z, it2->col);
00171           same_yval.clear();
00172         }
00173         cur_yval = y;
00174       }
00175       same_yval.insert(*it);
00176     }
00177   }
00178 }
00179 

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