// create data to draw a color cube // #include #include #include "ppm.h" // a point in three dimensions // typedef struct { double x, y, z; } Point; // screen row and column coordinates // typedef struct { int row, col; } RC; // global variables // double H, W; // screen height and width #if 0 Point Q = { 256, 256, 256 }; // screen center #endif Point C = { 512, 512, 512 }; // camera position Point // screen corners: S1 = { 256+64, 64, 256+128 }, // top left, S2 = { 128-64, 256+64, 256+128 }, // top right, S3 = { 256+128+64+16, 256-64+16, 128-32 }; // bottom left // screen plane defined by: x + y + z = D // #define D (3*256.0) // display a point // #define disp( P) printf( #P " = ( %g, %g, %g)\n", P.x, P.y, P.z) #if 0 // screen corners Si = Q + alpha * (Pi - Q), i = 1, 2, 3 // Q is the center point, Pi are big screen corners // #define alpha 0.5 Point scale( double a, Point q, Point p) { Point S; S.x = q.x + a*(p.x - q.x); S.y = q.y + a*(p.y - q.y); S.z = q.z + a*(p.z - q.z); return S; } #endif // dot product, each vector specified by two points // double dot( Point a1, Point a2, Point b1, Point b2) { return (a1.x-a2.x)*(b1.x-b2.x) + (a1.y-a2.y)*(b1.y-b2.y) + (a1.z-a2.z)*(b1.z-b2.z); } // distance between two points // double dist( Point a, Point b) { return sqrt( dot( a, b, a, b)); } #if 0 // testing Point A[] = { { 255, 255, 255 }, { 0, 255, 255 }, { 0, 0, 255 }, { 255, 0, 255 }, { 255, 255, 255 }, { 255, 0, 255 }, { 255, 0, 0 }, { 255, 255, 0 }, { 255, 255, 255 }, { 255, 255, 0 }, { 0, 255, 0 }, { 0, 255, 255 }, { 255, 255, 255 }, }; #endif // project point onto screen, return row,col coordinates // RC project( double x, double y, double z) { Point AP; double K = (D - x - y - z) / ((C.x - x) + (C.y - y) + (C.z - z)); // printf( "K = %g\n", K); AP.x = x + K*(C.x - x); AP.y = y + K*(C.y - y); AP.z = z + K*(C.z - z); // disp( AP); double num = dot( S2, S1, AP, S1); double d = dist( AP, S1); double c = num / (W*d); double s = sqrt(1-c*c); // printf( "c = %g, s = %g\n", c, s); RC rc = { d*s + 0.5, d*c + 0.5 }; return rc; } // set PPM color intensities for one point on the color cube // // R,G,B color values are equal to the x,y,z coordinates // void set_ppm( ppm a, int x, int y, int z, int i, int j) { RC rc = project( x, y, z); if( rc.row < 0 || rc.row >= a.rows || rc.col < 0 || rc.col >= a.cols) return; a.r[rc.row][rc.col] = x; a.g[rc.row][rc.col] = y; a.b[rc.row][rc.col] = z; #if 1 if( i == 0 || i == 255 || j == 0 || j == 255) // black lines on edges a.r[rc.row][rc.col] = a.g[rc.row][rc.col] = a.b[rc.row][rc.col] = 0; #endif } int main( void) { #if 0 Point // big screen corners: P1 = { 3*128, -3*128, 3*256 }, // top left, P2 = { -3*128, 3*128, 3*256 }, // top right, P3 = { 3*256, 0, 0 }, // bottom left S1 = scale( alpha, Q, P1); // screen corners S2 = scale( alpha, Q, P2); S3 = scale( alpha, Q, P3); #endif H = dist( S3, S1); // screen height W = dist( S2, S1); // screen width // printf( "H = %g, W = %g\n", H, W); #if 0 for( int i = 0; i < sizeof(A)/sizeof(Point); ++i) { RC rc = project( A[i].x, A[i].y, A[i].z); // printf( "row = %i, col = %i\n", row, col); printf( "%i %i\n", rc.col, rc.row); } #endif // create PPM screen plane // int rows = H + 0.5; int cols = W + 0.5; ppm a = ppm_new( rows, cols); // set screen all white // for( int row = 0; row < rows; ++row) for( int col = 0; col < cols; ++col) a.r[row][col] = a.g[row][col] = a.b[row][col] = 255; // color cube // int k = 255; for( int i = 0; i < 256; ++i) for( int j = 0; j < 256; ++j) { set_ppm( a, i, j, k, i, j); // top plane, blue = 255 set_ppm( a, k, i, j, i, j); // left plane, red = 255 set_ppm( a, i, k, j, i, j); // right plane, green = 255 } ppm_write( a); return 0; }