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;
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";
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)
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)
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)
00115 {
00116 swap(x1, x2); swap(y1, y2); swap(z1, z2);
00117 swap(c1, c2);
00118 }
00119 if( (flip_y = y1 > y2) )
00120 {
00121 y1 = -y1, y2 = -y2;
00122 }
00123 if( (swap_xy = y2-y1 > x2-x1) )
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;
00148
00149
00150
00151
00152 ScanLineSegment(round(p1.x), round(p1.y), p1.z, col1, round(p2.x), round(p2.y), p2.z, col2, &scanned_pnts);
00153
00154 ScanLineSegment(round(p1.x), round(p1.y), p1.z, col1, round(p3.x), round(p3.y), p3.z, col3, &scanned_pnts);
00155
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;
00159 set<ScannedResult> same_yval;
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