00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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, Point const* Tex, RGB const* Col) : x(X), y(Y), z(Z) { if(Tex) tex = *Tex; if(Col) col = *Col; }
00055
00056 bool operator<(ScannedResult const& rhs) const { return (y<rhs.y) || ( (y==rhs.y) && (x<rhs.x) ); }
00057
00058 int x, y;
00059 float z;
00060 Point tex;
00061 RGB col;
00062 };
00063
00064
00065 class Canvas
00066 {
00067 public:
00068 explicit Canvas(int resoH = 512, int resoV = 512) : hReso(resoH), vReso(resoV), filename("tmp.ppm"), data(0), z_buffer(0), tex_image(0) { init(); }
00069 ~Canvas() { delete [] data; delete [] z_buffer; }
00070
00071
00072 void SetTextureImage(Canvas* tex) { tex_image = tex; }
00073
00074 void Checkerboard(int sz=4, RGB col1 = White, RGB col2 = Black);
00075
00076 void Clear(RGB const&);
00077
00078 RGB* operator[] (int r) { assert(r>=0 && r<vReso); return data + r*hReso; }
00079 RGB& Pixel(int row, int col);
00080 float& Z(int row, int col);
00081
00082 void Line(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2);
00083
00084 void WireTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3);
00085
00086
00087 void SolidTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3);
00088
00089 void SolidTriangle(Point const& P1, Point const& tex1, Point const& P2, Point const& tex2, Point const& P3, Point const& tex3);
00090
00091 void SolidTriangle(Point const& P1, Point const& T1, RGB const& col1,
00092 Point const& P2, Point const& T2, RGB const& col2,
00093 Point const& P3, Point const& T3, RGB const& col3);
00094
00095 void SolidTriangle(Point const& P1, Point const* T1, RGB const* col1,
00096 Point const& P2, Point const* T2, RGB const* col2,
00097 Point const& P3, Point const* T3, RGB const* col3);
00098
00099
00100 void WritePPM(const char* = 0) const;
00101 void ReadPPM(const char* = 0);
00102
00103 int hReso, vReso;
00104 std::string filename;
00105
00106 RGB* data;
00107 private:
00108 float* z_buffer;
00109 Canvas* tex_image;
00110
00111 bool swap_xy, flip_y;
00112
00113 void init();
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 void scanLineSegment(int x1, int y1, float z1, Point const* tex1, RGB const* col1,
00124 int x2, int y2, float z2, Point const* tex2, RGB const* col2,
00125 set<ScannedResult>* output=0);
00126
00127
00128 void _scanLineSegment(int x1, int y1, float z1, Point const* tex1, RGB const* col1,
00129 int x2, int y2, float z2, Point const* tex2, RGB const* col2,
00130 set<ScannedResult>* output=0);
00131
00132 RGB texture_color(Point const& tex) const { return tex_image->Pixel( round((tex_image->vReso-1) * tex.y), round((tex_image->hReso-1) * tex.x) ); }
00133
00134 void writePixel(int X, int Y, float cur_z, Point const* tex, RGB const* col, set<ScannedResult>* output);
00135
00136 double eye_at;
00137 Point perspectiveProjection(Point const&);
00138 };
00139
00140 inline void Canvas :: writePixel(int X, int Y, float cur_z, Point const* tex, RGB const* col, set<ScannedResult>* output)
00141 {
00142 if(swap_xy) swap(X,Y);
00143 if(flip_y) Y = -Y;
00144
00145 if(output)
00146 {
00147 output->insert( ScannedResult(X, Y, cur_z, tex, col) );
00148 }
00149 else if( (X >= -hReso/2 && X < hReso/2) &&
00150 (Y >= -vReso/2 && Y < vReso/2) )
00151 {
00152 if( cur_z > Z(Y + vReso/2, X + hReso/2) )
00153 {
00154 Z(Y + vReso/2, X + hReso/2) = cur_z;
00155 Pixel(Y + vReso/2, X + hReso/2) = tex && col ? texture_color(*tex) * *col : (tex ? texture_color(*tex) : *col);
00156 }
00157 }
00158 }
00159
00160 inline RGB& Canvas :: Pixel(int row, int col)
00161 {
00162 if(row >= vReso) { cout << "row = " << row << endl; throw "row number overflow\n"; }
00163 if(row < 0) { cout << "1row = " << row << endl; throw "row number underflow\n"; }
00164 if(col >= hReso) { cout << "col = " << col << endl; throw "col number overrflow\n"; }
00165 if(col < 0) { cout << "col = " << col << endl; throw "col number underflow\n"; }
00166 return *(data + row * hReso + col);
00167 }
00168
00169 inline float& Canvas :: Z(int row, int col)
00170 {
00171 if(row >= vReso) { cout << "row = " << row << endl; throw "row number overflow\n"; }
00172 if(row < 0) { cout << "1row = " << row << endl; throw "row number underflow\n"; }
00173 if(col >= hReso) { cout << "col = " << col << endl; throw "col number overrflow\n"; }
00174 if(col < 0) { cout << "col = " << col << endl; throw "col number underflow\n"; }
00175 return *(z_buffer + row * hReso + col);
00176 }
00177
00178 inline Point Canvas :: perspectiveProjection(Point const& P)
00179 {
00180 double scale = eye_at / (eye_at - P.z);
00181 return Point(P.x * scale, P.y * scale, P.z);
00182 }
00183
00184 inline void Canvas :: SolidTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3)
00185 {
00186 SolidTriangle(P1, 0, &col1, P2, 0, &col2, P3, 0, &col3);
00187 }
00188
00189 inline void Canvas :: SolidTriangle(Point const& P1, Point const& tex1, Point const& P2, Point const& tex2, Point const& P3, Point const& tex3)
00190 {
00191 SolidTriangle(P1, &tex1, 0, P2, &tex2, 0, P3, &tex3, 0);
00192 }
00193 inline void Canvas :: SolidTriangle(Point const& P1, Point const& T1, RGB const& col1,
00194 Point const& P2, Point const& T2, RGB const& col2,
00195 Point const& P3, Point const& T3, RGB const& col3)
00196 {
00197 SolidTriangle(P1, &T1, &col1, P2, &T2, &col2, P3, &T3, &col3);
00198 }
00199
00200 inline void Canvas :: Line(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2)
00201 {
00202 Point p1 = perspectiveProjection(P1);
00203 Point p2 = perspectiveProjection(P2);
00204
00205 scanLineSegment(round(p1.x), round(p1.y), p1.z, 0, &col1, round(p2.x), round(p2.y), p2.z, 0, &col2);
00206 }
00207
00208 inline void Canvas :: WireTriangle(Point const& P1, RGB const& col1, Point const& P2, RGB const& col2, Point const& P3, RGB const& col3)
00209 {
00210 Line(P1, col1, P2, col2);
00211 Line(P1, col1, P3, col3);
00212 Line(P2, col2, P3, col3);
00213 }
00214
00215
00216
00217 }
00218
00219 #endif