
/*----------------------------------------------------------------------
 *                                    TIGA
 *          Copyright (C) 1989-1990  Texas Instruments Incorporated.
 *                            All Rights Reserved
 *----------------------------------------------------------------------
 *
 *         TIGA-340 Example Application:  3D Flight Simulator
 *
 *  This C code executes on the TMS34010 GSP, and communicates with the
 *  host (PC) processor through the TIGA Communications Driver.  The
 *  functions defined in this file are downloaded to the GSP as part of
 *  a TIGA relocatable object module.
 *----------------------------------------------------------------------
 * History:
 *     03/23/89...Original version written...................J. Van Aken
 *     12/07/89...Modified to use TIGA's page_flip/busy......W.S.Egr    
 *----------------------------------------------------------------------
 */
#include <gsptypes.h>        /* TIGA type definitions */
#include <gspglobs.h>        /* TIGA global variables */
#include <gspreg.h>         /* GSP register names */
#include "flytypes.h"        /* flight simulator type definitions */
#include "flyconst.h"        /* flight simulator constant definitions */

#define FALSE 0
#define TRUE !FALSE
/* Define size of working buffers to contain intermediate xyz coordinate
 * values representing successive vertices of polygon.  Each coordinate
 * value is 32 bits, and each vertex is specified by three coordinates.
 * Constant BUFSIZE is the size in bytes of each of 2 buffers.
 */

#define MAXVRTS   32      /* max. no. of vertices allowed in polygon */
#define BUFSIZE   (sizeof(POINT3D)*(MAXVRTS+5))  /* buf size in bytes */

extern double sqrt();
extern uchar *gsp_malloc();   /* TIGA core function */
extern CONFIG config;         /* TIGA configuration parameters */

static long trigfun();        /* cos,sin of yaw,pitch,roll */

/*------------------- Working buffer storage areas -------------------*/
DBASE3D *db3d;                /* database describing 3D scene */
static uchar *heap;           /* working storage for 3D pipeline */
static uchar buf0[BUFSIZE], buf1[BUFSIZE];  /* buffers for vertices */

/*------------- Global structures defined in this module -------------*/
CLIP3D    vpclip = { { 0,0,0,0,0,0,0,0,0 }, BUFSIZE, buf0, buf1, 0, 0 };
ZCHECK    ztest;      /* object size vs. distance test params      */
VIEWPOINT view;       /* viewpoint orientation and position */
VIEWINFO  vuparams;   /* sin and cos of yaw, pitch and roll angles */
long xyorigin=0;

/*---------- Parameters shared by functions in this module -----------*/
static NODE *root;     /* pointer to root node of binary tree database */
static VIEWPORT cpvp;  /* viewport for 3D cockpit window view */
static VIEWPORT ahvp;  /* viewport for artificial horizon meter */
static long airspeed;        /* aircraft speed */
static short score;          /* player's score */
static short collision;      /* aircraft collision with object */
static short ipanel_state;   /* redraw instrument panel to both bufs */
static short new_ipanel;     /* instrument panel enabled/disabled */
static short masher_state;   /* masher enabled/disabled */
static int earth_color, sky_color, sun_color;  /* horizon colors */
static int ip_black, ip_red, ip_green, ip_yellow;  /* instr. panel */
static int ip_orange, ip_blue, ip_pcolor, ip_mcolor, ip_fcolor, ip_scolor;


/*----------------------------------------------------------------------
 *
 *              Initialize GSP side of flight simulator.
 *
 *----------------------------------------------------------------------
 */
init_flygsp(vuport1, vuport2, dbptr, ipenable)
VIEWPORT *vuport1, *vuport2;
DBASE3D *dbptr;
short ipenable;
{
    short i;
    long j;

    db3d = dbptr;   /* point to 3D database */
    /* Point to root node of hierarchical 3D database. */
    root = (NODE *)(db3d->rootnode + (long)&db3d->rootnode);
    /* Working storage for 3D pipeline starts at end of database. */
    heap = (uchar *)(8*db3d->dbsize + (long)&db3d->dbsize);

    cpvp = vpclip.vp = *vuport1;   /* viewport = 3D cockpit window */
    ahvp = *vuport2;               /* viewport = artificial horizon */

    /* Parameters for testing object size (bounding radius) on screen */
    ztest.kvis = cpvp.d/RVIS - 1;  /* size limit for invisible object */
    ztest.kdot = cpvp.d/RDOT - 1;  /* size limit for dot-size object */
    ztest.knpc = cpvp.d/RNPC - 1;  /* size limit for no preclipping */

    /* Calculate x and y scaling factors Kx and Ky to convert viewing
     * pyramid to canonical clipping volume (a right pyramid).
     */
    vpclip.kx = (cpvp.d << 18) / cpvp.sx;   /* FIX18 format */
    vpclip.ky = (cpvp.d << 18) / cpvp.sy;

    /* Define colors for both monochrome and 16-color displays. */
    if (config.mode.disp_psize == 1) {      /* monochrome */
        earth_color = 0;
        sky_color   = 0xFFFFFFFF;
        sun_color   = 0x55555555;
        ip_black    = 0xFFFFFFFF;    /* art horz reticles   */
        ip_red      = 0x55555555;    /* art horz earth      */
        ip_green    = 0;             /* meter hand color #1 */
        ip_yellow   = 0;             /* meter hand color #2 */
        ip_orange   = 0xFFFFFFFF;    /* art horz sun        */
        ip_blue     = 0x00000000;    /* art horz sky        */
        ip_pcolor   = 0;             /* instrument panel    */
        ip_mcolor   = 0xFFFFFFFF;    /* meter cover         */
        ip_fcolor   = 0xFFFFFFFF;    /* meter face          */
        ip_scolor   = 0xFFFFFFFF;    /* scoreboard color    */
    } else {                                /* 16 colors */
        earth_color = EARTHCOLOR;
        sky_color   = SKYCOLOR;
        sun_color   = SUNCOLOR;
        ip_black    = GRAY5;         /* art horz reticles   */
        ip_red      = RED1;          /* art horz earth      */
        ip_green    = BLUGRN1;       /* meter hand color #1 */
        ip_yellow   = SUNCOLOR;      /* meter hand color #2 */
        ip_orange   = SUNCOLOR;      /* art horz sun        */
        ip_blue     = SKYCOLOR;      /* art horz sky        */
        ip_pcolor   = GRAY2;         /* instrument panel    */
        ip_mcolor   = GRAY3;         /* meter cover         */
        ip_fcolor   = GRAY5;         /* meter face          */
        ip_scolor   = SUNCOLOR;      /* scoreboard color    */
    }

    /* Initialize "masher" (bouncing cube). */
    if (db3d->bcdata)
        masher_state = TRUE;
    else
        masher_state = FALSE;   /* no masher if bcdata == NIL */
    collision = 0;

    /* Initialize aircraft instrument panel. */
    if (ipenable) {
        ipanel_state = TRUE;
        new_ipanel = 2;
    } else {
        ipanel_state = FALSE;
        new_ipanel = 0;
    }

    /* Initialize double frame buffers for animation. */
    set_draw_origin(0, 0);
    pageinit();
    for (i = 2; i > 0; --i) {
        pageflip();
        clear_page(ip_pcolor);
        setcolor1(ip_fcolor);
        draw_rect(2*cpvp.sx+1, 2*cpvp.sy+1, cpvp.xleft-1, cpvp.ytop-1);
    }
    load_palet();
}


/*----------------------------------------------------------------------
 *
 *        Draw 3D view seen through aircraft's cockpit window.
 *
 *----------------------------------------------------------------------
 */
draw_frame(newview, trigvals, speed, scoreval)
VIEWPOINT *newview;
VIEWINFO  *trigvals;
long  speed;
short scoreval;
{
    extern char *dbinterp();
    char *p;

    view     = *newview;
    vuparams = *trigvals;
    airspeed = speed;
    score = scoreval;
    if (masher_state)
        update_masher();      /* update position of bouncing cube */
    vpclip.vp = cpvp;         /* viewport = 3D cockpit window */
    p = dbinterp(root, heap);  /* interpret 3D database */
    xfrmlist(heap, p);                  /* transform all 3D vertices */

    while (page_busy())                 /* wait while page is scanned */
        ;
    /* Draw objects in 3D scene.  Monochrome or 16 colors? */
    horizon1(earth_color, sky_color);   /* draw horizon */
    sun();                              /* draw sun at noon */
    if (config.mode.disp_psize == 1)
        displist_mono(p);               /* monochrome stipple pattern */
    else
        displist_color(p);              /* 16 colors */
    if (collision) {                    /* simulate collision */
        set_clip_rect(2*cpvp.sx, 2*cpvp.sy, cpvp.xleft, cpvp.ytop);
        set_draw_origin(cpvp.cx, cpvp.cy);

        setcolor1(sun_color);
        fill_circle((4 - --collision)*(cpvp.sx/4), 0, 0);
    }

    if (new_ipanel) {
        --new_ipanel;
        init_ipanel();
    }
    if (ipanel_state) {
        vpclip.vp = ahvp;
        draw_ipanel();        /* draw instrument panel */
    }
    pageflip();
}


/*----------------------------------------------------------------------
 *
 *          Load 16-color palette specified in 3D database.
 *
 *----------------------------------------------------------------------
 */
load_palet()
{
    short i, j;

    if (config.mode.disp_psize == 4)             /* 4 bits per pixel */
        set_palet(16, 0, &db3d->palet[0]);
    else if (config.mode.disp_psize == 8)        /* 8 bits per pixel */
        for (i = j = 0; i <= 15; ++i, j += 17)
            set_palet(1, j, &db3d->palet[i]);
}


/*----------------------------------------------------------------------
 *
 * Test whether current position lies within bounding box of object.
 *
 *----------------------------------------------------------------------
 */
short collide(xyz)
POINT3D  *xyz;
{
    short status;

    if ((status = inbbox(xyz, root)) == 1)
        collision = 4;             /* we bumped into something */
    return (status);
}


/*----------------------------------------------------------------------
 *
 *  Draw sun at high noon.  Prior to calling this function, the clipping
 *  rectangle must be set to cockpit viewport limits, and drawing origin
 *  must be set to center of viewport.
 *
 *----------------------------------------------------------------------
 */
#define UZMIN    1024    /* min. size of divisor to maintain accuracy */

sun()
{
    int radius;
    long x, y, uzz, vzz, wzz;

    set_clip_rect(2*cpvp.sx, 2*cpvp.sy, cpvp.xleft, cpvp.ytop);
    set_draw_origin(cpvp.cx, cpvp.cy);
    radius = vpclip.vp.sx / 4;                  /* sun's radius */
    if ((uzz = view.uvw.wz>>15) > UZMIN) {
        vzz = view.uvw.uz >> 15;
        wzz = view.uvw.vz >> 15;
        x = vpclip.vp.d * vzz / uzz;
        y = vpclip.vp.d * wzz / uzz;
        /* draw sun only if it is visible in viewport */
        if ((abs(x) < vpclip.vp.sx + radius)
                && (abs(y) < vpclip.vp.sy + radius)) {
            setcolor1(sun_color);
            fill_circle(radius, x, y);
        }
    }
}


/*----------------------------------------------------------------------
 *
 *                 Support for double-buffered video.
 *
 *----------------------------------------------------------------------
 */
#define DIE   (INTENB+10)      /* GSP's display interrupt enable bit */
#define DIP   (INTPEND+10)     /* GSP's display interrupt pending bit */

static short drawpage, disppage;  /* drawing and display pages */

pageinit()             /* initialize both pages (buffers) */
{
    drawpage = 0;            /* buffer 0 = initial drawing page */
    disppage = 1;            /* buffer 1 = initial display page */
    page_flip(disppage,drawpage);
    while( page_busy() );
}


pageflip()             /* request swap of drawing and display buffers */
{
    if (config.mode.num_pages < 2)
        return;
    page_flip( disppage^=1, drawpage^=1 );
}


/*----------------------------------------------------------------------
 *
 *      Update position of bouncing cube (alias, the "Masher").
 *
 *----------------------------------------------------------------------
 */
#define HW      16          /* half width of "unmashed" bouncing cube */


toggle_masher()
{
    masher_state ^= TRUE;
}


update_masher()
{
    static int z = 12*HW, vz = 0;  /* cube altitude and velocity */
    int ztop, zbot;       /* altitude of top and bottom faces of cube */
    int r;                /* current half width of cube */
    double vol, ht;       /* cube volume and height */
    char *p;

    if (!masher_state)
        return;
    z += vz;
    if ((zbot = z - HW) < 0)
        zbot = 0;
    if ((ztop = z + HW) < HW/3)
        ztop = HW/3;
    if (z >= HW) {
        --vz;
        r = HW;
    } else {
        vz += 5;
        vol = 8 * HW * HW * HW;
        ht = ztop - zbot;
        r = sqrt(vol / ht);
    }
    zbot >>= 2;
    ztop >>= 2;
    r >>= 2;

    /* Update position and shape of bouncing cube. */
    p = (char *)(db3d->bcdata + (long)&db3d->bcdata);

    p[16] = -r;
    p[17] =  r;       /* vertex  4 */
    p[18] = zbot;

    p[20] = -r;
    p[21] =  r;       /* vertex  5 */
    p[22] = ztop;

    p[24] =  r;
    p[25] =  r;       /* vertex  6 */
    p[26] = zbot;

    p[28] =  r;
    p[29] =  r;       /* vertex  7 */
    p[30] = ztop;

    p[32] =  r;
    p[33] = -r;       /* vertex  8 */
    p[34] = zbot;

    p[36] =  r;
    p[37] = -r;       /* vertex  9 */
    p[38] = ztop;

    p[40] = -r;
    p[41] = -r;       /* vertex 10 */
    p[42] = zbot;

    p[44] = -r;
    p[45] = -r;       /* vertex 11 */
    p[46] = ztop;

    /* Update bounDing box of bounCing cube. */
    p = (char *)(db3d->bcbbox + (long)&db3d->bcbbox);

    p[4] = -r;
    p[5] = -r;       /* xmin, ymin, zmin */
    p[6] = zbot;

    p[8] =  r;
    p[9] =  r;       /* xmax, ymax, zmax */
    p[10] = ztop;

    /* Update bounDing box of scoring region under bounCing cube. */
    p[16] = -r;
    p[17] = -r;       /* xmin, ymin (zmin = constant 0) */

    p[20] =  r;
    p[21] =  r;       /* xmax, ymax, zmax */
    p[22] = zbot;
}


/*----------------------------------------------------------------------
 *
 *                       Draw instrument panel.
 *
 *----------------------------------------------------------------------
 */

init_ipanel()      /* initialize instrument panel at bottom of screen */
{
    short i, j;

    /* Fill in background behind individual meters in panel. */
    set_clip_rect(config.mode.disp_hres, IPHT,
                   0, config.mode.disp_vres-IPHT);
    set_draw_origin(0, config.mode.disp_vres-IPHT);
    setcolor1(ip_pcolor);            /* instrument panel */
    fill_rect(config.mode.disp_hres, IPHT, 0, 0);
    setcolor1(ip_fcolor);            /* instrument panel outline */
    draw_rect(config.mode.disp_hres-1, IPHT-1, 0, 0);
    if (!ipanel_state)
        return;

    /* If instruments active, draw frames around individual meters. */
    setcolor1(ip_mcolor);            /* meter frame */
    j = ahvp.ytop-config.mode.disp_vres+IPHT;
    for (i = ahvp.xleft-2*MSPACE; i <= ahvp.xleft+3*MSPACE; i += MSPACE)
        fill_rect(MDIAM, MDIAM, i, j);
}


toggle_ipanel()
{
    ipanel_state ^= TRUE;
    new_ipanel = 2;
}


draw_ipanel()
{
    static BIT N_symbol[] = {
        1,0,0,1,
        1,1,0,1,
        1,0,1,1,
        1,0,0,1,
        1,0,0,1,
    };
    static BIT S_symbol[] = {
        0,1,1,1,
        1,0,0,0,
        0,1,1,0,
        0,0,0,1,
        1,1,1,0,
    };
    static BIT E_symbol[] = {
        1,1,1,1,
        1,0,0,0,
        1,1,1,0,
        1,0,0,0,
        1,1,1,1,
    };
    static BIT W_symbol[] = {
        1,0,1,0,1,
        1,0,1,0,1,
        1,0,1,0,1,
        0,1,0,1,0,
        0,1,0,1,0,
    };
    static BIT UP_symbol[] = {
        1,0,1, 0, 1,1,1,
        1,0,1, 0, 1,0,1,
        1,0,1, 0, 1,1,1,
        1,0,1, 0, 1,0,0,
        1,1,1, 0, 1,0,0,
    };
    static BIT zero_symbol[] = {
        0,1,1,0,
        1,0,0,1,
        1,0,0,1,
        1,0,0,1,
        1,0,0,1,
        0,1,1,0,
    };
    static BIT SPEED_symbol[] = {
        1,1,1,0, 1,1,1,0, 1,1,1,0, 1,1,1,0, 1,1,0,
        1,0,0,0, 1,0,1,0, 1,0,0,0, 1,0,0,0, 1,0,1,
        1,1,1,0, 1,1,1,0, 1,1,0,0, 1,1,0,0, 1,0,1,
        0,0,1,0, 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,1,
        1,1,1,0, 1,0,0,0, 1,1,1,0, 1,1,1,0, 1,1,0,
    };
    static BIT ALT_symbol[] = {
        1,1,1,0, 1,0,0, 1,1,1,
        1,0,1,0, 1,0,0, 0,1,0,
        1,1,1,0, 1,0,0, 0,1,0,
        1,0,1,0, 1,0,0, 0,1,0,
        1,0,1,0, 1,1,1, 0,1,0,
    };
    static BIT SCORE_symbol[] = {
        1,1,1,0, 1,1,1,0, 1,1,1,0, 1,1,1,0, 1,1,1,0,
        1,0,0,0, 1,0,0,0, 1,0,1,0, 1,0,1,0, 1,0,0,0,
        1,1,1,0, 1,0,0,0, 1,0,1,0, 1,1,1,0, 1,1,0,0,
        0,0,1,0, 1,0,0,0, 1,0,1,0, 1,1,0,0, 1,0,0,0,
        1,1,1,0, 1,1,1,0, 1,1,1,0, 1,0,1,0, 1,1,1,0,
    };
    long uzz, vzz, wzz;
    long cs, sn, t;
    short xy[16];
    short i, x, ahcx, ahcy;

    if (!ipanel_state)
         return;
    ahcx = ahvp.xleft + MDIAM/2;   /* corner of artif. horzn. meter */
    ahcy = ahvp.ytop  + MDIAM/2;
    /*------------------------------ Tally pilot's score. */
    set_clip_rect(config.mode.disp_hres, IPHT,
                   0, config.mode.disp_vres-IPHT);
    set_draw_origin(ahvp.xleft-2*MSPACE, config.mode.disp_vres-IPHT+3);
    setcolor1(ip_pcolor);
    fill_rect(31+8*score, 5, 0, 0);
    if (score) {
        setcolors(ip_scolor, ip_pcolor);   /* yellow token */
        bit_expand(SCORE_symbol, 20, 20, 5, 0, 0);
        for (i = score, x = 26; i; --i, x += 8)
            fill_rect(5, 5, x, 0);
    }
    /*------------------------------ Draw air speed indicator. */
    set_draw_origin(ahcx-2*MSPACE, ahcy);
    setcolor1(ip_fcolor);
    fill_circle(MRADIUS, 0, 0);
    setcolors(ip_pcolor, ip_fcolor);
    bit_expand(zero_symbol, 4, 4, 6, -2, -21);
    bit_expand(SPEED_symbol, 19, 19, 5, -9, 13);

    trigfun(&cs, &sn, airspeed>>2, 8);

    xy[0] = -6 * cs -  9 * sn + (1<<6) >> 7;
    xy[1] = -6 * sn +  9 * cs + (1<<6) >> 7;

    xy[2] = -1 * cs + 36 * sn + (1<<6) >> 7;
    xy[3] = -1 * sn - 36 * cs + (1<<6) >> 7;

    xy[4] =  1 * cs + 36 * sn + (1<<6) >> 7;
    xy[5] =  1 * sn - 36 * cs + (1<<6) >> 7;

    xy[6] =  6 * cs -  9 * sn + (1<<6) >> 7;
    xy[7] =  6 * sn +  9 * cs + (1<<6) >> 7;

    setcolor1(ip_yellow);
    polygon(4, xy);

    /*------------------------------ Draw bank indicator. */
    set_draw_origin(ahcx-MSPACE, ahcy);
    setcolor1(ip_fcolor);
    fill_circle(MRADIUS, 0, 0);
    cs = vuparams.csrol >> 22;
    sn = vuparams.snrol >> 22;

    xy[0] =             36 * sn + (1<<6) >> 7;    /* tail */
    xy[1] =            -36 * cs + (1<<6) >> 7;

    xy[2] =   7 * cs            + (1<<6) >> 7;
    xy[3] =   7 * sn            + (1<<6) >> 7;

    xy[4] =  -7 * cs            + (1<<6) >> 7;
    xy[5] =  -7 * sn            + (1<<6) >> 7;

    xy[6] =  44 * cs + sn       + (1<<6) >> 7;    /* wing */
    xy[7] =  44 * sn - cs       + (1<<6) >> 7;

    xy[8] =  44 * cs - sn       + (1<<6) >> 7;
    xy[9] =  44 * sn + cs       + (1<<6) >> 7;

    xy[10] =             -7 * sn + (1<<6) >> 7;
    xy[11] =              7 * cs + (1<<6) >> 7;

    xy[12] = -44 * cs - sn       + (1<<6) >> 7;
    xy[13] = -44 * sn + cs       + (1<<6) >> 7;

    xy[14] = -44 * cs + sn       + (1<<6) >> 7;
    xy[15] = -44 * sn - cs       + (1<<6) >> 7;

    setcolor1(ip_green);
    polygon(3, xy);
    polygon(5, &xy[6]);

    /*------------------------------ Draw artificial horizon. */
    set_draw_origin(ahcx, ahcy);
    horizon0(ip_red, ip_blue);
    if (abs(wzz = view.uvw.wz>>15) > 128) {
        uzz = -view.uvw.uz >> 15;
        vzz = -view.uvw.vz >> 15;
        set_clip_rect(2*MRADIUS, 2*MRADIUS, ahcx-MRADIUS, ahcy-MRADIUS);
        setcolor1(ip_orange);
        draw_circle(MRADIUS>>1, -MRADIUS*uzz/wzz, -MRADIUS*vzz/wzz);
        set_clip_rect(config.mode.disp_hres, IPHT,
                                     0, config.mode.disp_vres-IPHT);
    }
    setcolor1(ip_black);
    draw_line(-12, 0, 12, 0);
    draw_line(0, 6, 0, -6);
    setcolor1(ip_mcolor);
    frame_hole(MRADIUS, 0, 0);

    /*---------------------------------- Draw direction indicator. */
    set_draw_origin(ahcx+MSPACE, ahcy);
    setcolor1(ip_fcolor);
    fill_circle(MRADIUS, 0, 0);
    setcolor1(ip_pcolor);
    bit_expand(N_symbol, 4, 4, 5, -2, -20);
    bit_expand(S_symbol, 4, 4, 5, -2, 15);
    bit_expand(E_symbol, 4, 4, 5, 16, -3);
    bit_expand(W_symbol, 5, 5, 5, -20, -3);
    cs = vuparams.csyaw >> 22;
    sn = vuparams.snyaw >> 22;

    xy[0] = -7 * sn -  9 * cs + (1<<6) >> 7;
    xy[1] = -7 * cs +  9 * sn + (1<<6) >> 7;

    xy[2] = -1 * sn + 33 * cs + (1<<6) >> 7;
    xy[3] = -1 * cs - 33 * sn + (1<<6) >> 7;

    xy[4] =  1 * sn + 33 * cs + (1<<6) >> 7;
    xy[5] =  1 * cs - 33 * sn + (1<<6) >> 7;

    xy[6] =  7 * sn -  9 * cs + (1<<6) >> 7;
    xy[7] =  7 * cs +  9 * sn + (1<<6) >> 7;

    setcolor1(ip_green);
    polygon(4, xy);
    fill_rect(2, 2, -1, -1);

    /*------------------------------ Draw altimeter. */
    set_draw_origin(ahcx+2*MSPACE, ahcy);
    setcolor1(ip_fcolor);
    fill_circle(MRADIUS, 0, 0);
    setcolor1(ip_pcolor);
    bit_expand(zero_symbol, 4, 4, 6, -2, -21);
    bit_expand(ALT_symbol, 10, 10, 5, -5, 12);

    trigfun(&cs, &sn, view.xyz.z>>8, 8);

    xy[0] = 0;
    xy[1] = 0;

    xy[2] = -6 * cs + 31 * sn + (1<<6) >> 7;
    xy[3] = -6 * sn - 31 * cs + (1<<6) >> 7;

    xy[4] =           43 * sn + (1<<6) >> 7;
    xy[5] =          -43 * cs + (1<<6) >> 7;

    xy[6] =  6 * cs + 31 * sn + (1<<6) >> 7;
    xy[7] =  6 * sn - 31 * cs + (1<<6) >> 7;

    setcolor1(ip_yellow);
    polygon(4, xy);

    trigfun(&cs, &sn, (view.xyz.z>>8)/10, 8);

    xy[0] = -3 * cs           + (1<<6) >> 7;
    xy[1] = -3 * sn           + (1<<6) >> 7;

    xy[2] = -1 * cs + 36 * sn + (1<<6) >> 7;
    xy[3] = -1 * sn - 36 * cs + (1<<6) >> 7;

    xy[4] =  1 * cs + 36 * sn + (1<<6) >> 7;
    xy[5] =  1 * sn - 36 * cs + (1<<6) >> 7;

    xy[6] =  3 * cs           + (1<<6) >> 7;
    xy[7] =  3 * sn           + (1<<6) >> 7;

    setcolor1(ip_green);
    polygon(4, xy);
    fill_rect(2, 2, -1, -1);

    /*------------------------------ Draw inst. vert. speed ind. */
    set_draw_origin(ahcx+3*MSPACE, ahcy);
    setcolor1(ip_fcolor);
    fill_circle(MRADIUS, 0, 0);
    setcolor1(ip_pcolor);
    bit_expand(UP_symbol, 7, 7, 5, -3, -18);
    bit_expand(zero_symbol, 4, 4, 6, -21, -3);

    if ((t = airspeed*(view.uvw.wz>>10)>>21) > 160*4)
        t = 160*4;
    else if (t < -160*4)
        t = -160*4;
    trigfun(&cs, &sn, t, 8);

    xy[0] = 0;
    xy[1] = 0;

    xy[2] = -6 * sn - 31 * cs + (1<<6) >> 7;
    xy[3] =  6 * cs - 31 * sn + (1<<6) >> 7;

    xy[4] =          -43 * cs + (1<<6) >> 7;
    xy[5] =          -43 * sn + (1<<6) >> 7;

    xy[6] =  6 * sn - 31 * cs + (1<<6) >> 7;
    xy[7] = -6 * cs - 31 * sn + (1<<6) >> 7;

    setcolor1(ip_yellow);
    polygon(4, xy);
    fill_rect(2, 2, -1, -1);
}


/*----------------------------------------------------------------------
 *  Sine lookup table for angles 0 to 90 degrees in 1/4-degree steps.
 *  Each sine value is expressed as a 32-bit fixed-point value with
 *  31 bits of fraction.
 *----------------------------------------------------------------------
 */
static long sintbl[] = {
    0x00000000, 0x008efa17, 0x011df37c, 0x01aceb7c,     /* 0 deg. */
    0x023be165, 0x02cad485, 0x0359c428, 0x03e8af9e,     /* 1 deg. */
    0x04779632, 0x05067734, 0x059551f1, 0x062425b6,     /* 2 deg. */
    0x06b2f1d2, 0x0741b592, 0x07d07044, 0x085f2137,     /* 3 deg. */
    0x08edc7b7, 0x097c6313, 0x0a0af299, 0x0a997598,     /* 4 deg. */
    0x0b27eb5c, 0x0bb65336, 0x0c44ac72, 0x0cd2f660,     /* 5 deg. */
    0x0d61304e, 0x0def598a, 0x0e7d7162, 0x0f0b7727,     /* 6 deg. */
    0x0f996a26, 0x102749af, 0x10b5150f, 0x1142cb98,     /* 7 deg. */
    0x11d06c97, 0x125df75b, 0x12eb6b35, 0x1378c774,     /* 8 deg. */
    0x14060b68, 0x1493365f, 0x152047ab, 0x15ad3e9a,     /* 9 deg. */
    0x163a1a7e, 0x16c6daa6, 0x17537e63, 0x17e00505,     /* 10 deg. */
    0x186c6ddd, 0x18f8b83c, 0x1984e373, 0x1a10eed3,     /* 11 deg. */
    0x1a9cd9ac, 0x1b28a351, 0x1bb44b14, 0x1c3fd045,     /* 12 deg. */
    0x1ccb3237, 0x1d56703c, 0x1de189a6, 0x1e6c7dc7,     /* 13 deg. */
    0x1ef74bf3, 0x1f81f37c, 0x200c73b4, 0x2096cbf1,     /* 14 deg. */
    0x2120fb83, 0x21ab01c0, 0x2234ddfb, 0x22be8f87,     /* 15 deg. */
    0x234815ba, 0x23d16fe8, 0x245a9d65, 0x24e39d85,     /* 16 deg. */
    0x256c6f9f, 0x25f51307, 0x267d8713, 0x2705cb19,     /* 17 deg. */
    0x278dde6e, 0x2815c06a, 0x289d7061, 0x2924edac,     /* 18 deg. */
    0x29ac37a0, 0x2a334d96, 0x2aba2ee4, 0x2b40dae2,     /* 19 deg. */
    0x2bc750e9, 0x2c4d9050, 0x2cd39871, 0x2d5968a3,     /* 20 deg. */
    0x2ddf0040, 0x2e645ea1, 0x2ee9831f, 0x2f6e6d16,     /* 21 deg. */
    0x2ff31bde, 0x30778ed2, 0x30fbc54d, 0x317fbeab,     /* 22 deg. */
    0x32037a45, 0x3286f779, 0x330a35a1, 0x338d341b,     /* 23 deg. */
    0x340ff242, 0x34926f74, 0x3514ab0e, 0x3596a46c,     /* 24 deg. */
    0x36185aee, 0x3699cdf2, 0x371afcd5, 0x379be6f6,     /* 25 deg. */
    0x381c8bb5, 0x389cea72, 0x391d028b, 0x399cd362,     /* 26 deg. */
    0x3a1c5c57, 0x3a9b9cca, 0x3b1a941c, 0x3b9941b1,     /* 27 deg. */
    0x3c17a4e8, 0x3c95bd26, 0x3d1389cb, 0x3d910a3c,     /* 28 deg. */
    0x3e0e3ddc, 0x3e8b240e, 0x3f07bc37, 0x3f8405bc,     /* 29 deg. */
    0x40000000, 0x407baa6a, 0x40f7045f, 0x41720d46,     /* 30 deg. */
    0x41ecc484, 0x42672981, 0x42e13ba4, 0x435afa54,     /* 31 deg. */
    0x43d464fb, 0x444d7aff, 0x44c63bcb, 0x453ea6c7,     /* 32 deg. */
    0x45b6bb5e, 0x462e78f9, 0x46a5df03, 0x471cece7,     /* 33 deg. */
    0x4793a210, 0x4809fdeb, 0x487fffe4, 0x48f5a767,     /* 34 deg. */
    0x496af3e2, 0x49dfe4c2, 0x4a547976, 0x4ac8b16b,     /* 35 deg. */
    0x4b3c8c12, 0x4bb008d9, 0x4c232730, 0x4c95e688,     /* 36 deg. */
    0x4d084651, 0x4d7a45fe, 0x4debe4fe, 0x4e5d22c6,     /* 37 deg. */
    0x4ecdfec7, 0x4f3e7875, 0x4fae8f43, 0x501e42a5,     /* 38 deg. */
    0x508d9211, 0x50fc7cfb, 0x516b02d9, 0x51d92321,     /* 39 deg. */
    0x5246dd49, 0x52b430c9, 0x53211d18, 0x538da1ae,     /* 40 deg. */
    0x53f9be05, 0x54657194, 0x54d0bbd6, 0x553b9c45,     /* 41 deg. */
    0x55a6125c, 0x56101d94, 0x5679bd6c, 0x56e2f15d,     /* 42 deg. */
    0x574bb8e6, 0x57b41384, 0x581c00b3, 0x58837ff4,     /* 43 deg. */
    0x58ea90c4, 0x595132a2, 0x59b76510, 0x5a1d278d,     /* 44 deg. */
    0x5a82799a, 0x5ae75ab9, 0x5b4bca6c, 0x5bafc837,     /* 45 deg. */
    0x5c13539b, 0x5c766c1c, 0x5cd91140, 0x5d3b428c,     /* 46 deg. */
    0x5d9cff83, 0x5dfe47ad, 0x5e5f1a91, 0x5ebf77b5,     /* 47 deg. */
    0x5f1f5ea1, 0x5f7ecedd, 0x5fddc7f3, 0x603c496c,     /* 48 deg. */
    0x609a52d3, 0x60f7e3b0, 0x6154fb91, 0x61b19a00,     /* 49 deg. */
    0x620dbe8b, 0x626968be, 0x62c49827, 0x631f4c54,     /* 50 deg. */
    0x637984d4, 0x63d34137, 0x642c810c, 0x648543e4,     /* 51 deg. */
    0x64dd8950, 0x653550e2, 0x658c9a2d, 0x65e364c4,     /* 52 deg. */
    0x6639b03b, 0x668f7c25, 0x66e4c818, 0x673993a9,     /* 53 deg. */
    0x678dde6e, 0x67e1a7ff, 0x6834eff3, 0x6887b5e2,     /* 54 deg. */
    0x68d9f964, 0x692bba14, 0x697cf78a, 0x69cdb162,     /* 55 deg. */
    0x6a1de737, 0x6a6d98a4, 0x6abcc547, 0x6b0b6cbd,     /* 56 deg. */
    0x6b598ea3, 0x6ba72a98, 0x6bf4403b, 0x6c40cf2c,     /* 57 deg. */
    0x6c8cd70b, 0x6cd8577a, 0x6d23501b, 0x6d6dc08f,     /* 58 deg. */
    0x6db7a87a, 0x6e010780, 0x6e49dd45, 0x6e92296e,     /* 59 deg. */
    0x6ed9eba1, 0x6f212385, 0x6f67d0c1, 0x6fadf2fc,     /* 60 deg. */
    0x6ff389df, 0x70389514, 0x707d1443, 0x70c10718,     /* 61 deg. */
    0x71046d3e, 0x71474660, 0x7189922c, 0x71cb504e,     /* 62 deg. */
    0x720c8075, 0x724d224f, 0x728d358c, 0x72ccb9db,     /* 63 deg. */
    0x730baeed, 0x734a1475, 0x7387ea23, 0x73c52fab,     /* 64 deg. */
    0x7401e4c1, 0x743e0918, 0x74799c66, 0x74b49e5f,     /* 65 deg. */
    0x74ef0ebc, 0x7528ed32, 0x7562397a, 0x759af34c,     /* 66 deg. */
    0x75d31a61, 0x760aae73, 0x7641af3d, 0x76781c7a,     /* 67 deg. */
    0x76adf5e6, 0x76e33b3f, 0x7717ec41, 0x774c08ab,     /* 68 deg. */
    0x777f903c, 0x77b282b3, 0x77e4dfd2, 0x7816a759,     /* 69 deg. */
    0x7847d909, 0x787874a7, 0x78a879f4, 0x78d7e8b6,     /* 70 deg. */
    0x7906c0b0, 0x793501a9, 0x7962ab67, 0x798fbdb0,     /* 71 deg. */
    0x79bc384d, 0x79e81b06, 0x7a1365a5, 0x7a3e17f2,     /* 72 deg. */
    0x7a6831ba, 0x7a91b2c7, 0x7aba9ae6, 0x7ae2e9e4,     /* 73 deg. */
    0x7b0a9f8d, 0x7b31bbb2, 0x7b583e21, 0x7b7e26aa,     /* 74 deg. */
    0x7ba3751d, 0x7bc8294d, 0x7bec430b, 0x7c0fc22a,     /* 75 deg. */
    0x7c32a67e, 0x7c54efdc, 0x7c769e18, 0x7c97b109,     /* 76 deg. */
    0x7cb82885, 0x7cd80464, 0x7cf7447f, 0x7d15e8ad,     /* 77 deg. */
    0x7d33f0ca, 0x7d515caf, 0x7d6e2c37, 0x7d8a5f40,     /* 78 deg. */
    0x7da5f5a5, 0x7dc0ef44, 0x7ddb4bfc, 0x7df50bab,     /* 79 deg. */
    0x7e0e2e32, 0x7e26b371, 0x7e3e9b4a, 0x7e55e59e,     /* 80 deg. */
    0x7e6c9251, 0x7e82a146, 0x7e981262, 0x7eace58a,     /* 81 deg. */
    0x7ec11aa5, 0x7ed4b198, 0x7ee7aa4c, 0x7efa04a8,     /* 82 deg. */
    0x7f0bc097, 0x7f1cde01, 0x7f2d5cd1, 0x7f3d3cf4,     /* 83 deg. */
    0x7f4c7e54, 0x7f5b20df, 0x7f692483, 0x7f76892f,     /* 84 deg. */
    0x7f834ed0, 0x7f8f7559, 0x7f9afcb9, 0x7fa5e4e1,     /* 85 deg. */
    0x7fb02dc6, 0x7fb9d759, 0x7fc2e18e, 0x7fcb4c5b,     /* 86 deg. */
    0x7fd317b4, 0x7fda4391, 0x7fe0cfe7, 0x7fe6bcb0,     /* 87 deg. */
    0x7fec09e3, 0x7ff0b77a, 0x7ff4c56f, 0x7ff833bd,     /* 88 deg. */
    0x7ffb0260, 0x7ffd3154, 0x7ffec096, 0x7fffb026,     /* 89 deg. */
    0x7fffffff                                          /* 90 deg. */
};


/*----------------------------------------------------------------------
 *  Given an angle t, calculate the values cos(t) and sin(t).  The first
 *  two arguments are pointers to the cosine and sine values,
 *  respectively.  Each value is a 32-bit fixed point value.  Argument t
 *  specifies the angle in degrees, and is a fixed-point number with 2
 *  bits of fraction.  Hence, angles can be specified to 1/4 degree.
 *  Argument n specifies the number of bits of fraction in the fixed
 *  point values for the sine and cosine.  For example, n = 8 specifies
 *  that the 8 LSBs of the cosine and sine values are the fractional
 *  parts of those values.  The range of allowed values for n is 1 to
 *  30.
 *
 *  The return value is angle t, which is unmodified if argument t was
 *  in the range 0 to 360*4-1. Otherwise, the return value is t
 *  converted to the equivalent angle in the range 0 to 360*4-1.
 *----------------------------------------------------------------------
 */
static long trigfun(cost, sint, t, n)
long *cost, *sint;  /* pointers to cosine and sine variables */
long t;             /* angle in degrees (fixed pt, 2 LSBs = fraction) */
short n;            /* no. of bits of fraction in cost and sint */
{
    /* restrict angle t to range 0 to 360 degrees */
    if ((t %= 360*4) < 0)
        t += 360*4;
    if (t < 180*4) {
        if (t < 90*4) {
            *cost =  (sintbl[90*4-t]  >> 31-n);
            *sint =  (sintbl[t]       >> 31-n);
        } else {
            *cost = -(sintbl[t-90*4]  >> 31-n);
            *sint =  (sintbl[180*4-t] >> 31-n);
        }
    } else {
        if (t < 270*4) {
            *cost = -(sintbl[270*4-t] >> 31-n);
            *sint = -(sintbl[t-180*4] >> 31-n);
        } else {
            *cost =  (sintbl[t-270*4] >> 31-n);
            *sint = -(sintbl[360*4-t] >> 31-n);
        }
    }
    return (t);
}

