/**
 ** scancnvx.c ---- scan fill a convex polygon
 **
 ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
 ** [e-mail: csaba@vuse.vanderbilt.edu]
 **
 ** This file is part of the GRX graphics library.
 **
 ** The GRX graphics library is free software; you can redistribute it
 ** and/or modify it under some conditions; see the "copying.grx" file
 ** for details.
 **
 ** This library is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 **
 **/

#include "libgrx.h"
#include "shapes.h"
#include "clipping.h"
#include "arith.h"
#include "shape/polyedge.h"

typedef struct {
    unsigned int dir;       /* which direction to go for next point */
    unsigned int index;     /* index of the current point */
    polyedge e;
} edge;

#define next_edge(ed,n,pt) {                            \
    ed.index   = (ed.index + ed.dir) % (unsigned int)n; \
    ed.e.x     = ed.e.xlast;                            \
    ed.e.y     = ed.e.ylast;                            \
    ed.e.xlast = pt[ed.index][0];                       \
    ed.e.ylast = pt[ed.index][1];                       \
}

void _GrScanConvexPoly(int n,int pt[][2],GrFiller *f,GrFillArg c)
{
    edge L,R;
    int  xmin,xmax;
    int  ymin,ymax;
    int  ypos,i;
    if((n > 1) &&
        (pt[0][0] == pt[n - 1][0]) &&
        (pt[0][1] == pt[n - 1][1])) {
            n--;
        }
    if(n < 1) {
        return;
    }

    xmin = xmax = pt[0][0];
    ymin = ymax = pt[0][1];
    ypos = 0;
    for(i = 1; i < n; i++) {
        int *ppt = pt[i];
        if(ymin > ppt[1]) ymin = ppt[1],ypos = i;
        if(ymax < ppt[1]) ymax = ppt[1];
        if(xmin > ppt[0]) xmin = ppt[0];
        if(xmax < ppt[0]) xmax = ppt[0];
    }
    clip_ordbox(CURC,xmin,ymin,xmax,ymax);
    mouse_block(CURC,xmin,ymin,xmax,ymax);
    L.dir	  = 1;
    R.dir	  = n - 1;
    L.index	  = R.index   = ypos;
    L.e.xlast = R.e.xlast = pt[ypos][0];
    L.e.ylast = R.e.ylast = pt[ypos][1];
    for( ; ; ) {
        next_edge(L,n,pt);
        if(L.e.ylast >= ymin) {
            clip_line_ymin(CURC,L.e.x,L.e.y,L.e.xlast,L.e.ylast);
            setup_edge(&L.e);
            break;
        }
    }
    for( ; ; ) {
        next_edge(R,n,pt);
        if(R.e.ylast >= ymin) {
            clip_line_ymin(CURC,R.e.x,R.e.y,R.e.xlast,R.e.ylast);
            setup_edge(&R.e);
            break;
        }
    }
    for(ypos = ymin; ypos <= ymax; ypos++) {
        xmin = L.e.x;
        xmax = L.e.x;
        if(ypos == L.e.ylast) {
            xmin = imin(xmin,L.e.xlast);
            xmax = imax(xmax,L.e.xlast);
            if(ypos < ymax) for( ; ; ) {
                next_edge(L,n,pt);
                if(L.e.ylast > ypos) {
                    setup_edge(&L.e);
                    break;
                }
                xmin = imin(xmin,L.e.xlast);
                xmax = imax(xmax,L.e.xlast);
            }
        }
        if(ypos != ymax) {
            if(L.e.xmajor) {
                xstep_edge(&L.e);
                xmin = imin(xmin,(L.e.x - L.e.xstep));
                xmax = imax(xmax,(L.e.x - L.e.xstep));
            }
            else {
                ystep_edge(&L.e);
            }
        }
        xmin = imin(xmin,R.e.x);
        xmax = imax(xmax,R.e.x);
        if(ypos == R.e.ylast) {
            xmin = imin(xmin,R.e.xlast);
            xmax = imax(xmax,R.e.xlast);
            if(ypos < ymax) for( ; ; ) {
                next_edge(R,n,pt);
                if(R.e.ylast > ypos) {
                    setup_edge(&R.e);
                    break;
                }
                xmin = imin(xmin,R.e.xlast);
                xmax = imax(xmax,R.e.xlast);
            }
        }
        if(ypos != ymax) {
            if(R.e.xmajor) {
                xstep_edge(&R.e);
                xmin = imin(xmin,(R.e.x - R.e.xstep));
                xmax = imax(xmax,(R.e.x - R.e.xstep));
            }
            else {
                ystep_edge(&R.e);
            }
        }
        clip_ordxrange_(CURC,xmin,xmax,continue,CLIP_EMPTY_MACRO_ARG);
        (*f->scan)((xmin + CURC->gc_xoffset),
                   (ypos + CURC->gc_yoffset),
                   (xmax - xmin + 1),c);
    }
    mouse_unblock();
}

