/*---------------------------------------------------------------------------- * vt.c * * This file contains the viewing transformation and perspective * transformation functions. *---------------------------------------------------------------------------- */ #include #include #include #include "defs.h" #include "ds.h" extern struct Window *window ; extern VIEW_TRANS view_trans ; extern ROTATION_INFO rot_info ; extern REF_AXES ref_axes [NUM_LINKS] ; initialize_viewing_transformation () { /*--------------------------------------------------------------------------- * Pre-calculate the viewing transformations to be used based on an * eye coordinate in the arms world coordinate system. * Display the arm after the 1st view transformation is calculated to * amuse the user while the rest are calculated. *--------------------------------------------------------------------------- */ static VIEWPOINT viewpoint = { { 0.0, 200.0, 0.0}, /* front view */ { 0.0, 0.0, 350.0}, /* top view */ { 200.0, 0.0, 0.0}, /* side view */ { 200.0, 200.0, 200.0}, /* angle 1 view */ {-100.0, 150.0, 350.0}, /* angle 2 view */ { 255.0, 180.0, -250.0} /* angle 3 view */ } ; viewing_transformation (viewpoint.angle1, view_trans.angle1) ; rot_info.curr_view_trans = (int *) &view_trans.angle1 ; transform_links () ; set_screen_coords () ; draw_image (window->RPort) ; viewing_transformation (viewpoint.front, view_trans.front) ; viewing_transformation (viewpoint.top, view_trans.top) ; viewing_transformation (viewpoint.side, view_trans.side) ; viewing_transformation (viewpoint.angle2, view_trans.angle2) ; viewing_transformation (viewpoint.angle3, view_trans.angle3) ; } viewing_transformation (vpoint, view_trans) float vpoint [3] ; int view_trans [4][4] ; { FFP fvpoint [3] ; int abs_vpt [3], fhypot1, fhypot2 ; int pos_theta, neg_theta ; int trans [NUM_MATRICES] [4][4] ; int i, k ; /*---------------------------------------------------------------------------- * Set the world coordinate arm vertices w.r.t the viewpoint. The viewpoint * is specified in world coordinates. The algorithm is based on the example * in Newman & Sproul "Principles of Interactive Computer Graphics" 2nd ed. * p.348. An accurate view from any octant in the world coordinate space * can be displayed, given an eye viewpoint. *---------------------------------------------------------------------------- */ /* set up conversion to Motorola FFP to speed up floating point operations */ for (i = X; i <= Z; ++i) { fvpoint [i].f = vpoint [i] ; fvpoint [i].i = SPFieee (fvpoint [i].i) ; abs_vpt [i] = SPAbs (fvpoint [i].i) ; } /* special cases such as front, side and top views can be treated */ /* separately for quicker handling */ /* top view */ if (SPCmp (fvpoint [X].i, ffp.zero.i) == 0 && SPCmp (fvpoint [Y].i, ffp.zero.i) == 0) { set_to_identity_matrix (view_trans) ; view_trans [0][0] = ffp.zero.i ; view_trans [1][0] = ffp.one.i ; view_trans [0][1] = ffp.one.i ; view_trans [1][1] = ffp.zero.i ; view_trans [2][2] = ffp.neg_one.i ; view_trans [3][2] = fvpoint [Z].i ; return (NULL) ; } /* front view */ if (SPCmp (fvpoint [X].i, ffp.zero.i) == 0 && SPCmp (fvpoint [Z].i, ffp.zero.i) == 0) { set_to_identity_matrix (view_trans) ; view_trans [0][0] = ffp.neg_one.i ; view_trans [1][1] = ffp.zero.i ; view_trans [2][1] = ffp.neg_one.i ; view_trans [2][2] = ffp.zero.i ; view_trans [1][2] = ffp.neg_one.i ; view_trans [3][2] = fvpoint [Y].i ; return (NULL) ; } /* side view */ if (SPCmp (fvpoint [Y].i, ffp.zero.i) == 0 && SPCmp (fvpoint [Z].i, ffp.zero.i) == 0) { set_to_identity_matrix (view_trans) ; view_trans [0][0] = ffp.zero.i ; view_trans [1][0] = ffp.one.i ; view_trans [1][1] = ffp.zero.i ; view_trans [2][1] = ffp.neg_one.i ; view_trans [0][2] = ffp.neg_one.i ; view_trans [2][2] = ffp.zero.i ; view_trans [3][2] = fvpoint [X].i ; return (NULL) ; } /* the messier viewing transformations follow */ /* initialize matrices used to the identity matrix */ for (k = 0; k < NUM_MATRICES; ++k) set_to_identity_matrix (trans [k]) ; /* trans [0] */ /* translate original world coordinate axes to eye coordinate axes */ trans [0] [3][0] = SPNeg (fvpoint [X].i) ; trans [0] [3][1] = SPNeg (fvpoint [Y].i) ; trans [0] [3][2] = SPNeg (fvpoint [Z].i) ; /* trans [1] */ /* rotate about the new X axis by 90 degrees so that the */ /* new Z axis cuts through the old ZX plane */ trans [1] [1][1] = trans [1] [2][2] = ffp.zero.i ; /* cos(90) is 0.0 */ if (SPCmp (fvpoint [Y].i, ffp.zero.i) == 1) { /* sin(-90) = -sin(90) */ trans [1] [1][2] = ffp.neg_one.i ; /* = -1 or +1 */ trans [1] [2][1] = ffp.one.i ; } else { trans [1] [1][2] = ffp.one.i ; trans [1] [2][1] = ffp.neg_one.i ; } /* trans [2] */ /* rotate about the new Y axis so that the new Z axis */ /* cuts the old Z axis */ fhypot1 = SPSqrt (SPAdd (SPMul (abs_vpt [X], abs_vpt [X]), SPMul (abs_vpt [Y], abs_vpt [Y]))) ; trans [2] [0][0] = trans [2] [2][2] = SPDiv (fhypot1, abs_vpt [X]) ; pos_theta = SPDiv (fhypot1, abs_vpt [Y]) ; neg_theta = SPNeg (pos_theta) ; if (SPCmp (fvpoint [X].i, ffp.zero.i) == 1) { trans [2] [2][0] = pos_theta ; trans [2] [0][2] = neg_theta ; } else { trans [2] [2][0] = neg_theta ; trans [2] [0][2] = pos_theta ; } /* trans [3] */ /* rotate about the new X axis so that the new Z axis */ /* passes through the old coordinate system origin */ fhypot2 = SPSqrt (SPAdd (SPMul (fhypot1, fhypot1), SPMul (abs_vpt [Z], abs_vpt [Z]))) ; trans [3] [1][1] = trans [3] [2][2] = SPDiv (fhypot2, fhypot1) ; pos_theta = SPDiv (fhypot1, abs_vpt [Z]) ; neg_theta = SPNeg (pos_theta) ; if (SPCmp (SPMul (fvpoint [Y].i, fvpoint [Z].i), ffp.zero.i) == 1) { trans [3] [2][1] = pos_theta ; trans [3] [1][2] = neg_theta ; } else { trans [3] [2][1] = neg_theta ; trans [3] [1][2] = pos_theta ; } /* trans [4] */ /* invert the X and Y axis depending on the viewpoint */ if (SPCmp (fvpoint [Y].i, ffp.zero.i) == 1) { trans [4] [1][1] = ffp.neg_one.i ; trans [4] [0][0] = ffp.neg_one.i ; } matrix_mult (trans [0], trans [1], trans [5]) ; matrix_mult (trans [5], trans [2], trans [0]) ; matrix_mult (trans [0], trans [3], trans [1]) ; matrix_mult (trans [1], trans [4], view_trans) ; } perspective_transformation (aperture) int aperture ; { int persp_trans [4][4] ; int zmax, zmin ; int temp ; /*--------------------------------------------------------------------------- * Create a perspective transformation based on the current post viewing * transformation coordinated. The algorithm is taken from Newman & Sproul * "Principles of Interactive Computer Graphics" 2nd ed. p.356. * The Z coordinate information is retained in a format suitable for * hidden surface removal. Face plane equations are still valid. * The aperture setting varies the ratio of the screen size to the * distance from the viewpoint. * The Z coordinates map into a range from 0 to 1, and the X, Y * coordinates map into the range -1 to +1. The closest object in the * current view will be at Z position 0, and the farthest at 1. * This transformation occasionally does strange things to the view. *--------------------------------------------------------------------------- */ find_max_min_coords (Z) ; zmax = arm.amax [Z] ; zmin = arm.amin [Z] ; set_to_identity_matrix (persp_trans) ; aperture = SPMul (aperture, zmin) ; temp = SPSub (SPDiv (zmax, zmin), ffp.one.i) ; persp_trans [2][2] = SPDiv (SPMul (temp, zmin), aperture) ; persp_trans [3][2] = SPDiv (temp, SPNeg (aperture)) ; persp_trans [2][3] = SPDiv (zmin, aperture) ; persp_trans [3][3] = ffp.zero.i ; transform_vertices_to_perspective (persp_trans) ; } transform_vertices_to_perspective (persp_trans) int persp_trans [4][4] ; { LINK_PTR l ; FACE_PTR f ; FFP_POINT_PTR p_curr ; int i, j, k ; /*--------------------------------------------------------------------------- * Run through all the arm vertices and transform them with the * perspective transformation. *--------------------------------------------------------------------------- */ l = &arm.link [UPPER] ; for (k = 0; k < NUM_LINKS; ++k) { f = &l->face[0] ; for (i = 0; i < l->num_faces; ++i) { p_curr = &f->ffp_curr_vertex[0] ; for (j = 0; j < f->num_vertices; ++j) transform_persp_pt (p_curr++, persp_trans) ; ++f ; } transform_ref_axes_persp (k, persp_trans) ; ++l ; } } transform_ref_axes_persp (joint, trans) int joint ; int trans [4][4] ; { FFP_POINT_PTR p_curr ; int i ; /*--------------------------------------------------------------------------- * Run through all the reference axes coordinates and transform them * with the perspective transformation. *--------------------------------------------------------------------------- */ p_curr = &ref_axes [joint].curr_coord [0] ; for (i = X; i <= ORIGIN; ++i) transform_persp_pt (p_curr++, trans) ; } transform_persp_pt (p_curr, persp_trans) int p_curr [] ; int persp_trans [4][4] ; { int temp [4] ; int i, j ; /*--------------------------------------------------------------------------- * Transform one point (vertex) with the perspective transformation. *--------------------------------------------------------------------------- */ for (i = X; i <= W; ++i) temp [i] = ffp.zero.i ; for (i = X; i <= W; ++i) for (j = X; j <= W; ++j) temp [i] = SPAdd (temp [i], SPMul (p_curr [j], persp_trans [j][i])) ; for (i = X; i <= W; ++i) p_curr [i] = SPDiv (temp [W], temp [i]) ; } set_to_identity_matrix (trans) int trans [4][4] ; { int i, j ; /*--------------------------------------------------------------------------- * Set "trans" to the identity matrix. Use Motorola FFP floats stored * in Lattice int variables. *--------------------------------------------------------------------------- */ for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) { if (i == j) trans [i][j] = ffp.one.i ; else trans [i][j] = ffp.zero.i ; } } } matrix_mult (t1, t2, r) int t1 [4][4], t2 [4][4], r [4][4] ; { /*--------------------------------------------------------------------------- * Optimized matrix multiplier using Motorola FFP routines. The float * values in the matrices are stored in "ints". * The result of multiplying 4x4 "t1" by 4x4 "t2" is returned in matrix "r". *--------------------------------------------------------------------------- */ int i, j, k ; for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) r [i][j] = ffp.zero.i ; for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) for (k = 0; k < 4; ++k) r [i][j] = SPAdd (r [i][j], SPMul (t1 [i][k], t2 [k][j])) ; }