/*--------------------------------------------------------------------------- * draw.c * * This file contains routines that calculate self hidden surfaces, * priorizes the link and face drawing order, and then displays the arm on * the screen. *--------------------------------------------------------------------------- */ #include #include #include #include "defs.h" #include "ds.h" draw_wire_frame_arm (rp) struct RastPort *rp ; { LINK_PTR l ; FACE_PTR f ; int *x, *y ; int firstx, firsty ; int i, j, k ; /*--------------------------------------------------------------------------- * Draw a wire frame view of the arm. The pre-calculated current int X * and Y coordinates are used. *--------------------------------------------------------------------------- */ SetAPen (rp, COLOR7) ; l = &arm.link [UPPER] ; for (k = 0; k < NUM_LINKS; ++k) { f = &l->face[0] ; for (i = 0; i < l->num_faces; ++i) { firstx = *(x = &f->x [0]) ; firsty = *(y = &f->y [0]) ; Move (rp, firstx, firsty) ; for (j = 1; j < f->num_vertices; ++j) Draw (rp, *(++x), *(++y)) ; Draw (rp, firstx, firsty) ; ++f ; } ++l ; } } draw_solid_arm (rp) struct RastPort *rp ; { LINK_PTR l ; FACE_PTR f ; int *x, *y, *ord_l ; int i, j, k ; /*--------------------------------------------------------------------------- * Draw a solid view of the arm with hidden surfaces removed. * The pre-calculated current int X and Y coordinates are used. * Back faces of solids are eliminated and the order of drawing the * links and hand faces are calculated, based on a simple average of the * maximum and minimum link (or hand face) Z coordinates. * It is not necessary to priorize the drawing order for the upper * and lower arm faces due to there simplicity. *--------------------------------------------------------------------------- */ mark_hidden_surfaces () ; priorize_draw_order () ; ord_l = arm.l_order ; for (k = 0; k < NUM_LINKS; ++k) { l = &arm.link [*ord_l++] ; if (l->num_faces == arm.link [HAND].num_faces) draw_hand (l, rp) ; else { f = &l->face [0] ; for (i = 0; i < l->num_faces; ++i) { if (f->visible) { SetAPen (rp, f->color) ; x = &f->x [0] ; y = &f->y [0] ; AreaMove (rp, *x, *y) ; for (j = 1; j < f->num_vertices; ++j) AreaDraw (rp, *(++x), *(++y)) ; AreaEnd (rp) ; } ++f ; } } } } draw_hand (l, rp) LINK_PTR l ; struct RastPort *rp ; { FACE_PTR f ; int *x, *y, *ord_f ; int i, j ; /*---------------------------------------------------------------------------- * Draw the hand. A face is drawn if it is visible (not a back plane of * a solid). The hand faces are drawn in the order specified in the * "arm.link [HAND].f_order [MAX_FACES]" array. This array contains the * correct index order to draw the hand faces. *---------------------------------------------------------------------------- */ ord_f = l->f_order ; for (i = 0; i < l->num_faces; ++i) { f = &l->face [*ord_f++] ; if (f->visible) { SetAPen (rp, f->color) ; x = &f->x [0] ; y = &f->y [0] ; AreaMove (rp, *x, *y) ; for (j = 1; j < f->num_vertices; ++j) AreaDraw (rp, *(++x), *(++y)) ; AreaEnd (rp) ; } } } mark_hidden_surfaces () { LINK_PTR l ; FACE_PTR f ; FFP_POINT_PTR p1, p2, p0 ; int *c1, *c2 ; int x1X, x1Y, x1Z, x2X, x2Y, x2Z ; int a, b, c, d, t1, ; int i, j, k ; /*--------------------------------------------------------------------------- * Calculate back planes of all the arm links. The plane equation for each * face is calculated using the equation in David Rogers "Procedural * Elements for Computer Graphics", p.209. The dot product of the face * normal and a vector at infinity (directly behind the viewpoint) is * calculated. The sign of the result determines whether the face is on the * back side of an object. *-------------------------------------------------------------------------- */ l = &arm.link [UPPER] ; for (k = 0; k < NUM_LINKS; ++k) { f = &l->face[0] ; for (i = 0; i < l->num_faces; ++i) { p0 = p1 = &f->ffp_curr_vertex [0] ; p2 = &f->ffp_curr_vertex [1] ; a = b = c = ffp.zero.i ; for (j = 1; j < f->num_vertices; ++j) { c1 = (int *) p1 ; c2 = (int *) p2 ; x1X = *(c1+X) ; x1Y = *(c1+Y) ; x1Z = *(c1+Z) ; x2X = *(c2+X) ; x2Y = *(c2+Y) ; x2Z = *(c2+Z) ; a = SPAdd (a, SPMul (SPSub (x2Y, x1Y), SPAdd (x2Z, x1Z) )) ; b = SPAdd (b, SPMul (SPSub (x2Z, x1Z), SPAdd (x2X, x1X) )) ; c = SPAdd (c, SPMul (SPSub (x2X, x1X), SPAdd (x2Y, x1Y) )) ; ++p1 ; ++p2 ; } c1 = (int *) p1 ; c2 = (int *) p0 ; x1X = *(c1+X) ; x1Y = *(c1+Y) ; x1Z = *(c1+Z) ; x2X = *(c2+X) ; x2Y = *(c2+Y) ; x2Z = *(c2+Z) ; a = SPAdd (a, SPMul (SPSub (x2Y, x1Y), SPAdd (x2Z, x1Z) )) ; b = SPAdd (b, SPMul (SPSub (x2Z, x1Z), SPAdd (x2X, x1X) )) ; c = SPAdd (c, SPMul (SPSub (x2X, x1X), SPAdd (x2Y, x1Y) )) ; d = SPNeg (SPAdd (SPMul (a, x2X), SPAdd (SPMul (b, x2Y), SPMul (c, x2Z )))) ; f->plane_eqn [X] = a ; f->plane_eqn [Y] = b ; f->plane_eqn [Z] = c ; f->plane_eqn [W] = d ; t1 = hidden_surface_dot_product (f->plane_eqn) ; if (SPCmp (t1, ffp.zero.i) == 1) f->visible = NO ; else f->visible = YES ; ++f ; } ++l ; } } hidden_surface_dot_product (plane_eqn) int plane_eqn [] ; { int sum, i; /*--------------------------------------------------------------------------- * Take the dot product of the plane equation and a pre-calculated * FFP point at infinity. *--------------------------------------------------------------------------- */ sum = ffp.zero.i ; for (i = 0; i < 4; ++i) sum = SPAdd (sum, SPMul (plane_eqn [i], ffp.test_pt [i].i)) ; return (sum) ; } priorize_draw_order () { LINK_PTR l ; FACE_PTR f ; int link_sort [NUM_LINKS] ; int face_sort [MAX_FACES] ; int i ; /*--------------------------------------------------------------------------- * Priorize the drawing order of the arm links and hand faces in order * to remove surfaces hidden by other parts of the arm. * The average of the maximum and minimum link (or face) Z coordinates is * calculated and stored in an array to be sorted. The indices of the * sorted links (or faces) are stored in the "f_order[]" and "l_order[]", * arrays in the arm data structure. *--------------------------------------------------------------------------- */ find_max_min_coords (Z) ; l = &arm.link [0] ; f = &arm.link [HAND].face [0] ; for (i = 0; i < NUM_LINKS; ++i) { link_sort [i] = SPDiv (ffp.two.i, SPAdd (l->lmin [Z], l->lmax [Z])) ; ++l ; } for (i = 0; i < arm.link [HAND].num_faces; ++i) { face_sort [i] = SPDiv (ffp.two.i, SPAdd (f->fmin [Z], f->fmax [Z])) ; ++f ; } sort_items (link_sort, NUM_LINKS, arm.l_order) ; sort_items (face_sort, arm.link [HAND].num_faces, arm.link [HAND].f_order) ; } sort_items (array, num, order) int array [], num, order [] ; { int max_z, i, j, k ; /*--------------------------------------------------------------------------- * Destructively sort the array items and store the original indices of * the sorted elements in another array. This sorting technique is commonly * referred to as the "stupid sort". Not a lot of items to sort though. *--------------------------------------------------------------------------- */ for (i = 0; i < num; ++i) { max_z = ffp.small_num.i ; for (j = 0; j < num; ++j) { if (SPCmp (array [j], max_z) == 1) { max_z = array [j] ; k = j ; } } array [k] = ffp.small_num.i ; order [i] = k ; } }