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
00023
00024 void Canvas :: WritePPM(const char *_filename) const
00025 {
00026 Canvas* This = (Canvas*)this;
00027
00028 if(!_filename)
00029 _filename = filename.c_str();
00030
00031 ofstream file;
00032 file.open (_filename, ios::out | ios::binary);
00033
00034 if(file)
00035 {
00036 file << "P6\n";
00037 file << hReso << " " << vReso << endl << 100 << endl;
00038
00039 unsigned char r, g, b;
00040 for (int row = 0; row < vReso; row++)
00041 for (int col = 0; col < hReso; col++)
00042 {
00043 r = (unsigned char) (100.0*(*This)[vReso-row-1][col][0]);
00044 g = (unsigned char) (100.0*(*This)[vReso-row-1][col][1]);
00045 b = (unsigned char) (100.0*(*This)[vReso-row-1][col][2]);
00046
00047 if(r>100.0 || g>100.0 || b>100.0) throw "RGB color overflow\n";
00048
00049 file << r << g << b;
00050 }
00051
00052 file << endl;
00053 file.close();
00054 }
00055 else
00056 cerr << "Can't open output file " << _filename << endl;
00057 }
00058
00059
00060 void Canvas :: scanLineSegment(int x1, int y1, RGB const& col1, int x2, int y2, RGB const& col2, multimap<int, int>* output)
00061 {
00062 assert( x2-x1 >= 1 && x2-x1 >= y2-y1 && y2-y1 >= 0);
00063
00064 for(int x = x1; x != x2; ++x)
00065 {
00066 double t = ( double(x-x1) ) / (x2 - x1);
00067 int y = round( interpolate(t, double(y1), double(y2)) );
00068
00069 int X = x, Y = y;
00070
00071 if(swap_xy)
00072 {
00073 swap(X,Y);
00074 }
00075 if(flip_y) Y = -Y-1;
00076
00077 if(output)
00078 output->insert(make_pair(Y, X));
00079 else
00080 (*this)[Y + vReso/2][X + hReso/2] = interpolate(t, col1, col2);
00081 }
00082 }
00083
00084
00085 void Canvas :: ScanLineSegment(int x1, int y1, RGB const& col1, int x2, int y2, RGB const& col2, multimap<int,int>* output)
00086 {
00087 if(x1==x2 && y1==y2) return;
00088
00089 if(x1 > x2)
00090 {
00091 swap(x1, x2), swap(y1, y2);
00092 swap( ((RGB&)col1), ((RGB&)col2) );
00093 }
00094 if( (flip_y = y1 > y2) )
00095 {
00096 y1 = -y1, y2 = -y2;
00097 }
00098 if( (swap_xy = y2-y1 > x2-x1) )
00099 {
00100 swap(x1, y1), swap(x2, y2);
00101 }
00102 scanLineSegment(x1, y1, col1, x2, y2, col2, output);
00103 }
00104
00105
00106 void Canvas :: SolidTriangle(int x1, int y1, RGB const& col1, int x2, int y2, RGB const& col2, int x3, int y3, RGB const& col3)
00107 {
00108 multimap<int, int> scanned_pnts;
00109
00110 ScanLineSegment(x1,y1,White, x2,y2,White, &scanned_pnts);
00111 ScanLineSegment(x1,y1,White, x3,y3,White, &scanned_pnts);
00112 ScanLineSegment(x3,y3,White, x2,y2,White, &scanned_pnts);
00113
00114 int cur_yval = vReso / 2;
00115 vector<int> xvals;
00116
00117 for (multimap<int, int>::iterator it = scanned_pnts.begin(); it != scanned_pnts.end(); ++it)
00118 {
00119 int y = it->first;
00120 if(y != cur_yval)
00121 {
00122 if(xvals.size())
00123 {
00124 int xleft = *( min_element( xvals.begin(), xvals.end() ) );
00125 int xright = *( max_element( xvals.begin(), xvals.end() ) );
00126 ScanLineSegment(xleft, cur_yval, White, xright, cur_yval, White);
00127 xvals.clear();
00128 }
00129 cur_yval = y;
00130 }
00131 xvals.push_back(it->second);
00132 }
00133 }
00134
00135 }