/* -*-mode:c-*- */ /*************************************************************** * * Radiosity * * Graphic driver for PostScript * * ***************************************************************/ #include #include #include "pslib.h" #define SCREEN_WIDTH (6.0*72) #define SCREEN_HEIGHT (4.8*72) #define SCREEN_DEPTH (65536) #define ASPECT_RATIO ((float)SCREEN_WIDTH/(float)SCREEN_HEIGHT) #define PRE_CAT (1) #define POST_CAT (0) #define DEFAULT_WINDOW_HEIGHT (2000.0) #define DEFAULT_WINDOW_WIDTH (DEFAULT_WINDOW_HEIGHT*ASPECT_RATIO) #define DEFAULT_FRONT_PLANE_Z (2000.0) #define DEFAULT_BACK_PLANE_Z (-4000.0) #define DEFAULT_PRP_Z (10000.0) /* Projection point Z coord. */ /************************************************** * * Globals * ***************************************************/ static Matrix trans_mtx ; /* WC -> DC */ static Vertex2 prp ; /* Projection point */ static Vertex2 active_prp ; /* Projection point in effect (WC) */ static float view_rotx, view_roty ; /* Viewing */ static float view_zoom ; static float clip_right, clip_left ; /* View volume (X) */ static float clip_top, clip_bottom ; /* (Y) */ static float clip_front, clip_back ; /* (Z) */ static FILE *ps_fd ; static void setup_transformation(void); static void init_transformation(void); static void gset_unit_matrix(Matrix *mtx); static void gconcatenate_matrix(long precat, Matrix *m1, Matrix *m2); static void gscale_matrix(long precat, Matrix *m1, float sx, float sy, float sz); static void gtranslate_matrix(long precat, Matrix *m1, float tx, float ty, float tz); static void grotate_x_matrix(long precat, Matrix *m1, float rot); static void grotate_y_matrix(long precat, Matrix *m1, float rot); static void gtransform(Vertex2 *v1, Vertex2 *v2, Matrix *mtx); static void ginverse_matrix(Matrix *m1, Matrix *m2); static double det(Matrix *m); static double cdet(Matrix *m, long r0, long r1, long r2, long c0, long c1, long c2); /************************************************************************ * * ps_open() * ps_close() * *************************************************************************/ long ps_open(char *file) { if( (ps_fd = fopen( file, "w" )) == 0 ) { perror( file ) ; return( 0 ) ; } /* Print out preamble */ fprintf( ps_fd, "%%!PS-Adobe-1.0\n" ) ; fprintf( ps_fd, "%%%%EndComments\n" ) ; fprintf( ps_fd, "%%%%Pages: 1\n" ) ; fprintf( ps_fd, "%%%%EndProlog\n" ) ; fprintf( ps_fd, "%%%%Page: 1 1\n" ) ; fprintf( ps_fd, "\n" ) ; /* Default line cap/join */ fprintf( ps_fd, "1 setlinecap 1 setlinejoin\n" ) ; /* Initialize transformation */ init_transformation() ; setup_transformation() ; return(0); } void ps_close() { if( ps_fd == 0 ) return ; fprintf( ps_fd, "showpage\n" ) ; fprintf( ps_fd, "%%%%Trailer\n" ) ; fclose( ps_fd ) ; ps_fd = 0 ; } /************************************************** * * ps_linewidth() * ***************************************************/ void ps_linewidth(float w) { if( ps_fd == 0 ) return ; fprintf( ps_fd, "%f setlinewidth\n", w ) ; } /************************************************** * * ps_line() * ***************************************************/ void ps_line(Vertex *p1, Vertex *p2) { Vertex2 v1, v2 ; float x1, y1, x2, y2 ; if( ps_fd == 0 ) return ; v1.v[0] = p1->x ; v1.v[1] = p1->y ; v1.v[2] = p1->z ; v1.v[3] = 1.0 ; v2.v[0] = p2->x ; v2.v[1] = p2->y ; v2.v[2] = p2->z ; v2.v[3] = 1.0 ; gtransform( &v1, &v1, &trans_mtx ) ; gtransform( &v2, &v2, &trans_mtx ) ; x1 = v1.v[0] / v1.v[3] ; y1 = v1.v[1] / v1.v[3] ; x2 = v2.v[0] / v2.v[3] ; y2 = v2.v[1] / v2.v[3] ; fprintf( ps_fd, "newpath\n%f %f moveto\n", x1, y1 ) ; fprintf( ps_fd, "%f %f lineto\nstroke\n", x2, y2 ) ; } /************************************************** * * ps_polygonedge() * ***************************************************/ void ps_polygonedge(long n, Vertex *p_list) { float dcx, dcy ; Vertex2 v ; long i ; if( ps_fd == 0 ) return ; /* Transform */ v.v[0] = p_list[0].x ; v.v[1] = p_list[0].y ; v.v[2] = p_list[0].z ; v.v[3] = 1.0 ; gtransform( &v, &v, &trans_mtx ) ; dcx = v.v[0] / v.v[3] ; dcy = v.v[1] / v.v[3] ; fprintf( ps_fd, "newpath\n%f %f moveto\n", dcx, dcy ) ; for( i = 1 ; i < n ; i++ ) { /* Transform */ v.v[0] = p_list[i].x ; v.v[1] = p_list[i].y ; v.v[2] = p_list[i].z ; v.v[3] = 1.0 ; gtransform( &v, &v, &trans_mtx ) ; dcx = v.v[0] / v.v[3] ; dcy = v.v[1] / v.v[3] ; fprintf( ps_fd, "%f %f lineto\n", dcx, dcy ) ; } fprintf( ps_fd, "closepath stroke\n" ) ; } /************************************************** * * ps_polygon() * ***************************************************/ void ps_polygon(long n, Vertex *p_list) { float dcx, dcy ; Vertex2 v ; long i ; if( ps_fd == 0 ) return ; /* Transform */ v.v[0] = p_list[0].x ; v.v[1] = p_list[0].y ; v.v[2] = p_list[0].z ; v.v[3] = 1.0 ; gtransform( &v, &v, &trans_mtx ) ; dcx = v.v[0] / v.v[3] ; dcy = v.v[1] / v.v[3] ; fprintf( ps_fd, "newpath\n%f %f moveto\n", dcx, dcy ) ; for( i = 1 ; i < n ; i++ ) { /* Transform */ v.v[0] = p_list[i].x ; v.v[1] = p_list[i].y ; v.v[2] = p_list[i].z ; v.v[3] = 1.0 ; gtransform( &v, &v, &trans_mtx ) ; dcx = v.v[0] / v.v[3] ; dcy = v.v[1] / v.v[3] ; fprintf( ps_fd, "%f %f lineto\n", dcx, dcy ) ; } fprintf( ps_fd, "closepath fill\n" ) ; } /************************************************** * * ps_spolygon() * ***************************************************/ void ps_spolygon(long n, Vertex *p_list, Rgb *c_list) { float dcx, dcy ; Vertex2 v ; long i ; float gray_scale ; if( ps_fd == 0 ) return ; /* Transform */ v.v[0] = p_list[0].x ; v.v[1] = p_list[0].y ; v.v[2] = p_list[0].z ; v.v[3] = 1.0 ; gtransform( &v, &v, &trans_mtx ) ; dcx = v.v[0] / v.v[3] ; dcy = v.v[1] / v.v[3] ; fprintf( ps_fd, "newpath\n%f %f moveto\n", dcx, dcy ) ; for( i = 1 ; i < n ; i++ ) { /* Transform */ v.v[0] = p_list[i].x ; v.v[1] = p_list[i].y ; v.v[2] = p_list[i].z ; v.v[3] = 1.0 ; gtransform( &v, &v, &trans_mtx ) ; dcx = v.v[0] / v.v[3] ; dcy = v.v[1] / v.v[3] ; fprintf( ps_fd, "%f %f lineto\n", dcx, dcy ) ; } gray_scale = c_list[0].g ; if( gray_scale > 1.0 ) gray_scale = 1.0 ; else if( gray_scale < 0.0 ) gray_scale = 0.0 ; fprintf( ps_fd, "closepath %f setgray fill\n", gray_scale ) ; } /************************************************** * * ps_clear() * ***************************************************/ void ps_clear() { } /************************************************** * * ps_setup_view() * ***************************************************/ void ps_setup_view(float rot_x, float rot_y, float dist, float zoom) { prp.v[0] = 0.0 ; prp.v[1] = 0.0 ; prp.v[2] = (float)dist ; prp.v[3] = 0.0 ; view_rotx = rot_x ; view_roty = rot_y ; view_zoom = zoom ; setup_transformation() ; } /************************************************** * * setup_transformation() * ***************************************************/ static void setup_transformation() { float cf_z, cb_z ; Matrix pmat ; /* Set to unit matrix */ gset_unit_matrix( &trans_mtx ) ; /* View orientation matrix */ grotate_x_matrix( POST_CAT, &trans_mtx, view_rotx ) ; grotate_y_matrix( POST_CAT, &trans_mtx, view_roty ) ; /* Compute active (currently effective) projection point */ ginverse_matrix( &pmat, &trans_mtx ) ; gtransform( &active_prp, &prp, &pmat ) ; /* Perspective projection */ gset_unit_matrix( &pmat ) ; pmat.m[2][3] = - 1 / prp.v[2] ; gconcatenate_matrix( POST_CAT, &trans_mtx, &pmat ) ; cf_z = prp.v[2] * clip_front / ( prp.v[2] - clip_front ) ; cb_z = prp.v[2] * clip_back / ( prp.v[2] - clip_back ) ; /* Window-Viewport */ gscale_matrix( POST_CAT, &trans_mtx, (float)SCREEN_WIDTH / (clip_right - clip_left), (float)SCREEN_HEIGHT / (clip_top - clip_bottom), (float)SCREEN_DEPTH / (cf_z - cb_z) ) ; gtranslate_matrix( POST_CAT, &trans_mtx, -(float)SCREEN_WIDTH * clip_left / (clip_right - clip_left), -(float)SCREEN_HEIGHT* clip_top / (clip_bottom - clip_top), -(float)SCREEN_DEPTH * cb_z / (cf_z - cb_z) ) ; gtranslate_matrix( POST_CAT, &trans_mtx, (float)(1.0*72), (float)(0.5*72), 0 ) ; } /************************************************** * * init_transformation() * ***************************************************/ static void init_transformation() { /* Initialize matrix, just in case */ gset_unit_matrix( &trans_mtx ) ; /* Initialize Projection point */ prp.v[0] = 0.0 ; prp.v[1] = 0.0 ; prp.v[2] = DEFAULT_PRP_Z ; prp.v[3] = 0.0 ; /* Viewing */ view_rotx = view_roty = 0.0 ; view_zoom = 1.0 ; /* Initialize view volume boundary */ clip_right = DEFAULT_WINDOW_WIDTH / 2.0 ; clip_left = -DEFAULT_WINDOW_WIDTH / 2.0 ; clip_top = DEFAULT_WINDOW_HEIGHT / 2.0 ; clip_bottom= -DEFAULT_WINDOW_HEIGHT / 2.0 ; clip_front = DEFAULT_FRONT_PLANE_Z ; clip_back = DEFAULT_BACK_PLANE_Z ; } /******************************************** * * set_unit_matrix() * *********************************************/ static void gset_unit_matrix(Matrix *mtx) { long row, col ; /* Clear the matrix */ for( row = 0 ; row < 4 ; row++ ) for( col = 0 ; col < 4 ; col++ ) mtx->m[row][col] = 0.0 ; /* Set 1.0s along diagonal line */ for( row = 0 ; row < 4 ; row++ ) mtx->m[row][row] = 1.0 ; } /******************************************** * * concatenate_matrix() * * m1 <- m1 * m2 (precat = 1) * m1 <- m2 * m1 (precat = 0) * *********************************************/ static void gconcatenate_matrix(long precat, Matrix *m1, Matrix *m2) { long row, col, scan ; Matrix *dest ; Matrix temp ; /* Swap pointer according to the concatenation mode */ dest = m1 ; if( precat == 1 ) { m1 = m2 ; m2 = dest ; } /* concatenate it */ for( row = 0 ; row < 4 ; row++ ) for( col = 0 ; col < 4 ; col++ ) { temp.m[row][col] = 0.0 ; for( scan = 0 ; scan < 4 ; scan++ ) temp.m[row][col] += m1->m[row][scan] * m2->m[scan][col]; } *dest = temp ; } /******************************************** * * scale_matrix() * * m1 <- SCALE * m1 (precat = 1) * m1 <- m1 * SCALE (precat = 0) * *********************************************/ static void gscale_matrix(long precat, Matrix *m1, float sx, float sy, float sz) { Matrix smat ; /* Initialize to unit matrix */ gset_unit_matrix( &smat ) ; /* Set scale values */ smat.m[0][0] = sx ; smat.m[1][1] = sy ; smat.m[2][2] = sz ; /* concatenate */ gconcatenate_matrix( precat, m1, &smat ) ; } /******************************************** * * translate_matrix() * * m1 <- T * m1 (precat = 1) * m1 <- m1 * T (precat = 0) * *********************************************/ static void gtranslate_matrix(long precat, Matrix *m1, float tx, float ty, float tz) { Matrix tmat ; /* Initialize to unit matrix */ gset_unit_matrix( &tmat ) ; /* Set scale values */ tmat.m[3][0] = tx ; tmat.m[3][1] = ty ; tmat.m[3][2] = tz ; /* concatenate */ gconcatenate_matrix( precat, m1, &tmat ) ; } /******************************************** * * rotate_x_matrix() * rotate_y_matrix() * rotate_z_matrix() * * m1 <- ROT * m1 (precat = 1) * m1 <- m1 * ROT (precat = 0) * *********************************************/ static void grotate_x_matrix(long precat, Matrix *m1, float rot) { Matrix rmat ; float s_val, c_val ; /* Initialize to unit matrix */ gset_unit_matrix( &rmat ) ; /* Set scale values */ s_val = sin( rot * M_PI / 180.0 ) ; c_val = cos( rot * M_PI / 180.0 ) ; rmat.m[1][1] = c_val ; rmat.m[1][2] = s_val ; rmat.m[2][1] = -s_val ; rmat.m[2][2] = c_val ; /* concatenate */ gconcatenate_matrix( precat, m1, &rmat ) ; } static void grotate_y_matrix(long precat, Matrix *m1, float rot) { Matrix rmat ; float s_val, c_val ; /* Initialize to unit matrix */ gset_unit_matrix( &rmat ) ; /* Set scale values */ s_val = sin( rot * M_PI / 180.0 ) ; c_val = cos( rot * M_PI / 180.0 ) ; rmat.m[0][0] = c_val ; rmat.m[0][2] = -s_val ; rmat.m[2][0] = s_val ; rmat.m[2][2] = c_val ; /* concatenate */ gconcatenate_matrix( precat, m1, &rmat ) ; } /******************************************** * * transform() * * v1 <- v2 * mtx * *********************************************/ static void gtransform(Vertex2 *v1, Vertex2 *v2, Matrix *mtx) { float x, y, z, w ; x = v2->v[0] * mtx->m[0][0] ; y = v2->v[0] * mtx->m[0][1] ; z = v2->v[0] * mtx->m[0][2] ; w = v2->v[0] * mtx->m[0][3] ; x += v2->v[1] * mtx->m[1][0] ; y += v2->v[1] * mtx->m[1][1] ; z += v2->v[1] * mtx->m[1][2] ; w += v2->v[1] * mtx->m[1][3] ; x += v2->v[2] * mtx->m[2][0] ; y += v2->v[2] * mtx->m[2][1] ; z += v2->v[2] * mtx->m[2][2] ; w += v2->v[2] * mtx->m[2][3] ; x += v2->v[3] * mtx->m[3][0] ; y += v2->v[3] * mtx->m[3][1] ; z += v2->v[3] * mtx->m[3][2] ; w += v2->v[3] * mtx->m[3][3] ; v1->v[0] = x ; v1->v[1] = y ; v1->v[2] = z ; v1->v[3] = w ; } /******************************************** * * inverse_matrix() * * m1 <- inv(m2) * *********************************************/ static void ginverse_matrix(Matrix *m1, Matrix *m2) { double detval ; /* det(m2) */ detval = det( m2 ) ; /* Clamel's solution */ m1->m[0][0] = cdet( m2, 1,2,3, 1,2,3 ) / detval ; m1->m[0][1] = -cdet( m2, 0,2,3, 1,2,3 ) / detval ; m1->m[0][2] = cdet( m2, 0,1,3, 1,2,3 ) / detval ; m1->m[0][3] = -cdet( m2, 0,1,2, 1,2,3 ) / detval ; m1->m[1][0] = -cdet( m2, 1,2,3, 0,2,3 ) / detval ; m1->m[1][1] = cdet( m2, 0,2,3, 0,2,3 ) / detval ; m1->m[1][2] = -cdet( m2, 0,1,3, 0,2,3 ) / detval ; m1->m[1][3] = cdet( m2, 0,1,2, 0,2,3 ) / detval ; m1->m[2][0] = cdet( m2, 1,2,3, 0,1,3 ) / detval ; m1->m[2][1] = -cdet( m2, 0,2,3, 0,1,3 ) / detval ; m1->m[2][2] = cdet( m2, 0,1,3, 0,1,3 ) / detval ; m1->m[2][3] = -cdet( m2, 0,1,2, 0,1,3 ) / detval ; m1->m[3][0] = -cdet( m2, 1,2,3, 0,1,2 ) / detval ; m1->m[3][1] = cdet( m2, 0,2,3, 0,1,2 ) / detval ; m1->m[3][2] = -cdet( m2, 0,1,3, 0,1,2 ) / detval ; m1->m[3][3] = cdet( m2, 0,1,2, 0,1,2 ) / detval ; } static double det(Matrix *m) { double det_sum ; /* Expand with respect to column 4 */ det_sum = 0.0 ; if( m->m[0][3] != 0.0 ) det_sum -= m->m[0][3] * cdet( m, 1, 2, 3, 0, 1, 2 ) ; if( m->m[1][3] != 0.0 ) det_sum += m->m[1][3] * cdet( m, 0, 2, 3, 0, 1, 2 ) ; if( m->m[2][3] != 0.0 ) det_sum -= m->m[2][3] * cdet( m, 0, 1, 3, 0, 1, 2 ) ; if( m->m[3][3] != 0.0 ) det_sum += m->m[3][3] * cdet( m, 0, 1, 2, 0, 1, 2 ) ; return( det_sum ) ; } static double cdet(Matrix *m, long r0, long r1, long r2, long c0, long c1, long c2) { double temp ; temp = m->m[r0][c0] * m->m[r1][c1] * m->m[r2][c2] ; temp += m->m[r1][c0] * m->m[r2][c1] * m->m[r0][c2] ; temp += m->m[r2][c0] * m->m[r0][c1] * m->m[r1][c2] ; temp -= m->m[r2][c0] * m->m[r1][c1] * m->m[r0][c2] ; temp -= m->m[r1][c0] * m->m[r0][c1] * m->m[r2][c2] ; temp -= m->m[r0][c0] * m->m[r2][c1] * m->m[r1][c2] ; return( temp ) ; }