#include "vizual.h"

/* LOCALLY Global structures */
static file_info *Headp;
static struct dspec *B_spec;
static struct Cap *Cap;
static struct poly_info Polys[3 * (MAXTHRESH + 1)];
static int x, y;

static double Xlinterp();

#define ANTICLOCKWISE 0
#define CLOCKWISE     1

/**************************************  get_min_max  *************************/
/* get min and max values from the original data */
static get_min_max(minmax, size, array) double *minmax;
int size;
double array[4];
{
    register int i;
    double min, max;

    min = max = *array;

    for (i = 0; i < size; i++) {
        if (array[i] > max)
            max = array[i];
        else if (array[i] < min)
            min = array[i];
    }

    minmax[0] = min;
    minmax[1] = max;
}

/*************************************** side_to_xy  **************************/
static side_to_xy(xyray, pre, zz, side) double *xyray;
struct poly_info *pre;
double zz;
int side;
{
    double x1, x2;
    double y1, y2;
    int side2;
    double interp;

    side2 = next_higher(side, pre->vnum);

    x1 = pre->verts[side << 1];
    y1 = pre->verts[(side << 1) + 1];
    x2 = pre->verts[side2 << 1];
    y2 = pre->verts[(side2 << 1) + 1];
    /*
       debugf("%lf x1  %lf y1\n",x1,y1);
       debugf("%lf x2  %lf y2\n",x2,y2);
     */

    interp = Xlinterp(pre->data[side], zz, pre->data[side2]);

    if (x1 != x2)
        xyray[0] = x1 + (interp * (x2 - x1));
    else
        xyray[0] = x1;
    if (y1 != y2)
        xyray[1] = y1 + (interp * (y2 - y1));
    else
        xyray[1] = y2;
}

/**********************************  split_poly   *****************************/
/* recursively subdivides polygons until no more threshold divide
 ** them then draws the polygon and falls thru to left over polygon
 ** code */

void split_poly(ta, pnum, t) int pnum; /* index to current polygon */
int ta;                                /* current threshold array */
int t;                                 /* current threshold index */
{
    double minmax[2];
    double zz; /* current threshold */
    int num;
    int hits;
    int xing[4]; /* a list of the sides with hits */
    int tnum;
    int i;
    int new_pnum;
    int side;
    static int first;
    int n_verts;
    cmndln_info *tp;
    int drawn;

    num = 0;
    hits = 0;
    drawn = 0;

    tp = &(B_spec->threshes[ta]);

    if (t >= tp->nthres)
        return;

    zz = (double)tp->tvalue[t];

    if (t) { /* don't draw below 1st threshold */
        if (B_spec->in_out == INSIDE)
            tnum = t + B_spec->low;
        else if (ta == 0)
            /* tnum == t; */ /* fix ? MN 2001 */
            tnum = t;
        else
            tnum = t + B_spec->hi;
    }

    /* calc min/max for each new poly */
    get_min_max(minmax, Polys[pnum].vnum, Polys[pnum].data);

    if (zz > (double)minmax[1]) { /* if entirely contained */
        if (t) {
            draw_cappolys(Headp, B_spec, Cap, &Polys[pnum], x, y, 1, tnum);
        }

        /*and we are done */
        return;
    }
    /* thresh in square */
    else if (WITHIN((double)minmax[0], zz, (double)minmax[1])) {

        /* this code from contour program:  determine number of crossings (hits)
         ** if non-zero and even, then have 1 or 2 valid contours in cell
         */
        for (i = 0; i < Polys[pnum].vnum; i++) {
            if ((Polys[pnum].data[i] <= zz &&
                 zz < Polys[pnum].data[(i + 1) % Polys[pnum].vnum]) ||
                (Polys[pnum].data[i] > zz &&
                 zz >= Polys[pnum].data[(i + 1) % Polys[pnum].vnum])) {
                hits |= (1 << i); /* record which lines were crossed */
                xing[num] = i;
                num++;
            }
        }

        if (!num || num & 0x01) { /* zero or odd  no contour in cell */
            /* just go on to next thresh */
            split_poly(ta, pnum, t + 1);
        }

        /* else split into two polygons */
        else {
            /* NUMBER OF XINGS = 2 */
            /* split the polygon and the reiterate */
            side = xing[0];
            /* first is set to true if the first split polygon is to be drawn */
            first = (zz > Polys[pnum].data[side]) ? 0 : 1;

            new_pnum = pnum + 1;
            n_verts = 0;

            /* 1st vert will be the location where the first xing occurs */
            /* not only are the vertices stored in the poly_info variable
             ** but also the data values at these vertices must be stored */
            Polys[new_pnum].data[n_verts] = zz;
            side_to_xy(&(Polys[new_pnum].verts[n_verts << 1]), &(Polys[pnum]),
                       zz, side);
            n_verts++;
            side = next_higher(side, Polys[pnum].vnum);

            while (side != xing[1]) {
                Polys[new_pnum].data[n_verts] = Polys[pnum].data[side];
                Polys[new_pnum].verts[n_verts << 1] =
                    Polys[pnum].verts[side << 1];
                Polys[new_pnum].verts[(n_verts << 1) + 1] =
                    Polys[pnum].verts[(side << 1) + 1];
                n_verts++;

                side = next_higher(side, Polys[pnum].vnum);
            }
            Polys[new_pnum].data[n_verts] = Polys[pnum].data[side];
            Polys[new_pnum].verts[n_verts << 1] = Polys[pnum].verts[side << 1];
            Polys[new_pnum].verts[(n_verts << 1) + 1] =
                Polys[pnum].verts[(side << 1) + 1];
            n_verts++;

            Polys[new_pnum].data[n_verts] = zz;
            side_to_xy(&(Polys[new_pnum].verts[n_verts << 1]), &(Polys[pnum]),
                       zz, side);
            n_verts++;

            Polys[new_pnum].vnum = n_verts;
            Polys[new_pnum].data[n_verts] = Polys[new_pnum].data[0];

            if (first) {
                if (t)
                    draw_cappolys(Headp, B_spec, Cap, &Polys[new_pnum], x, y, 1,
                                  tnum);
                drawn = 1;
            }
            else {
                split_poly(ta, new_pnum, t + 1);
            }

            /*============================================================================*/
            /* NOW DO THE SECOND HALF OF THE SPLIT */
            side = xing[1];
            n_verts = 0;

            /* 1st vert will be the location that xing occurs */
            Polys[new_pnum].data[n_verts] = zz;
            side_to_xy(&Polys[new_pnum].verts[n_verts << 1], &(Polys[pnum]), zz,
                       side);
            n_verts++;

            side = next_higher(side, Polys[pnum].vnum);
            while (side != xing[0]) {
                Polys[new_pnum].data[n_verts] = Polys[pnum].data[side];
                Polys[new_pnum].verts[n_verts << 1] =
                    Polys[pnum].verts[side << 1];
                Polys[new_pnum].verts[(n_verts << 1) + 1] =
                    Polys[pnum].verts[(side << 1) + 1];
                n_verts++;

                side = next_higher(side, Polys[pnum].vnum);
            }
            Polys[new_pnum].data[n_verts] = Polys[pnum].data[side];
            Polys[new_pnum].verts[n_verts << 1] = Polys[pnum].verts[side << 1];
            Polys[new_pnum].verts[(n_verts << 1) + 1] =
                Polys[pnum].verts[(side << 1) + 1];
            n_verts++;

            Polys[new_pnum].data[n_verts] = zz;
            side_to_xy(&Polys[new_pnum].verts[n_verts << 1], &(Polys[pnum]), zz,
                       side);
            n_verts++;

            Polys[new_pnum].vnum = n_verts;
            Polys[new_pnum].data[n_verts] = Polys[new_pnum].data[0];

            if (!first) {
                if (t) {
                    draw_cappolys(Headp, B_spec, Cap, &Polys[new_pnum], x, y, 1,
                                  tnum);
                }
                /* mark a flag */
                drawn = 1;
            }
            else {
                split_poly(ta, new_pnum, t + 1);
            }
        }
    } /*end WITHIN code */

    /* if no hits then ready to fall thru to left over node
       code which will be the tail end of the split_poly routine */

    if ((t < tp->nthres) && !drawn) {
        split_poly(ta, pnum, t + 1);
    }
    return;
}

/**************************************  Xlinterp  ****************************/
/* rescale zz to a number between 0. and 1. */
static double Xlinterp(zmin, zz, zmax)
double zmin, zz, zmax;
{
    if (zmin == zmax) /* div by zero.  should never get here */
        return zmin;
    return (zz - zmin) / (zmax - zmin);
}

/*******************************   next_higher  *******************************/
/* given sides 0,1,2,3, return number of next side in clockwise order */
int next_higher(side, verts)
int side, verts;
{
    return ((side + 1) % verts);
}

int draw_cap(XHeadp, XB_spec, XCap)
file_info *XHeadp;
struct dspec *XB_spec;
struct Cap *XCap;
{
    int row, xdim;
    int ta;
    cmndln_info *tp;
    int org_tnum;

    /* if flat shading */
    Headp = XHeadp;
    if (Headp->linefax.litmodel == 1)
        glDisable(GL_COLOR_MATERIAL);
    else {
        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
        glEnable(GL_COLOR_MATERIAL);
    }
    B_spec = XB_spec;
    Cap = XCap;

    xdim = Cap->Cols;
    for (y = Cap->miny; y < Cap->maxy; y++) { /* for each cell */
        row = y * Cap->Cols; /*shouldn't this be Rows? JCM   NO. DPG */
        for (x = Cap->minx; x < Cap->maxx; x++) {
            Polys[0].data[0] = Polys[0].data[4] =
                (double)Cap->D_buff[row + xdim + x];
            /*BL*/ Polys[0].data[1] =
                (double)Cap->D_buff[row + xdim + x + 1];         /* BR */
            Polys[0].data[2] = (double)Cap->D_buff[row + x + 1]; /* TR */
            Polys[0].data[3] = (double)Cap->D_buff[row + x];     /* TL */

            /* for each threshold array */
            for (ta = 0; ta < 2 && (tp = &(B_spec->threshes[ta]))->nthres;
                 ta++) {

                { /* build initial poly */
                    Polys[0].verts[0] = 0.0;
                    Polys[0].verts[1] = 1.0;
                    Polys[0].verts[2] = 1.0;
                    Polys[0].verts[3] = 1.0;
                    Polys[0].verts[4] = 1.0;
                    Polys[0].verts[5] = 0.0;
                    Polys[0].verts[6] = 0.0;
                    Polys[0].verts[7] = 0.0;
                    Polys[0].verts[8] = 0.0;
                    Polys[0].verts[9] = 1.0;
                    Polys[0].vnum = 4;
                }
                /* First time */
                if (B_spec->in_out == INSIDE)
                    org_tnum = B_spec->low;
                else
                    org_tnum = ta == 0 ? 0 : B_spec->hi;

                split_poly(ta, 0, 0);
            }
        }
    }
    glDisable(GL_COLOR_MATERIAL);
}
