/****************************************************************************\
*
* Dirty region calculation
*
* 14-Feb-1995 mikeke    Created
*
* Copyright (c) 1994 Microsoft Corporation
\****************************************************************************/

#include "precomp.h"
#pragma hdrstop

/****************************************************************************/

PXLIST XLISTAlloc(
    __GLGENbuffers *buffers)
{
    PXLIST pxlist;

    if (buffers->pxlist != NULL) {
        pxlist = buffers->pxlist;
        buffers->pxlist = pxlist->pnext;
    } else {
        pxlist = (PXLIST)ALLOC(sizeof(XLIST));
        if (pxlist == NULL) return NULL;
    }

    pxlist->pnext = NULL;
    return pxlist;
}

/****************************************************************************/

void XLISTFree(
    __GLGENbuffers *buffers,
    PXLIST pxlist)
{
    pxlist->pnext = buffers->pxlist;
    buffers->pxlist = pxlist;
}

/****************************************************************************/

PXLIST XLISTCopy(
    __GLGENbuffers *buffers,
    PXLIST pxlist)
{
    PXLIST pxlistNew = XLISTAlloc(buffers);

    if (pxlistNew != NULL) {
        pxlistNew->s = pxlist->s;
        pxlistNew->e = pxlist->e;
    }

    return pxlistNew;
}

/****************************************************************************/

BOOL YLISTAddSpan(
    __GLGENbuffers *buffers,
    PYLIST pylist,
    int xs,
    int xe)
{
    PXLIST *ppxlist = &(pylist->pxlist);
    PXLIST pxlist = XLISTAlloc(buffers);

    if (pxlist == NULL) return FALSE;

    //
    // Create new x span
    //

    pxlist->s = xs;
    pxlist->e = xe;

    //
    // Insert it in sorted order
    //

    while (
              ((*ppxlist) != NULL)
           && ((*ppxlist)->s < xs)
          ) {
        ppxlist = &((*ppxlist)->pnext);
    }
    pxlist->pnext = *ppxlist;
    *ppxlist = pxlist;

    //
    // Combine any overlapping spans
    //

    pxlist = pylist->pxlist;
    while (TRUE) {
        PXLIST pxlistNext = pxlist->pnext;

        if (pxlistNext == NULL) return TRUE;

        if (pxlist->e >= pxlistNext->s) {
            if (pxlistNext->e > pxlist->e) {
                pxlist->e = pxlistNext->e;
            }
            pxlist->pnext = pxlistNext->pnext;
            XLISTFree(buffers, pxlistNext);
        } else {
            pxlist = pxlist->pnext;
        }
    }

    return TRUE;
}

/****************************************************************************/

PYLIST YLISTAlloc(
    __GLGENbuffers *buffers)
{
    PYLIST pylist;

    if (buffers->pylist != NULL) {
        pylist = buffers->pylist;
        buffers->pylist = pylist->pnext;
    } else {
        pylist = (PYLIST)ALLOC(sizeof(YLIST));
        if (pylist == NULL) return NULL;
    }

    pylist->pxlist = NULL;
    pylist->pnext = NULL;
    return pylist;
}

/****************************************************************************/

void YLISTFree(
    __GLGENbuffers *buffers,
    PYLIST pylist)
{
    PXLIST pxlist = pylist->pxlist;
    PXLIST pxlistKill;

    while (pxlist != NULL) {
        pxlistKill = pxlist;
        pxlist = pxlist->pnext;
        XLISTFree(buffers, pxlistKill);
    }

    pylist->pnext = buffers->pylist;
    buffers->pylist = pylist;
}

/****************************************************************************/

PYLIST YLISTCopy(
    __GLGENbuffers *buffers,
    PYLIST pylist)
{
    PXLIST pxlist = pylist->pxlist;
    PXLIST *ppxlist;
    PYLIST pylistNew = YLISTAlloc(buffers);

    if (pylistNew != NULL) {
        pylistNew->s = pylist->s;
        pylistNew->e = pylist->e;

        ppxlist = &(pylistNew->pxlist);
        while (pxlist != NULL) {
            *ppxlist = XLISTCopy(buffers, pxlist);
            if (*ppxlist == NULL) {
                YLISTFree(buffers, pylistNew);
                return NULL;
            }
            ppxlist = &((*ppxlist)->pnext);
            pxlist = pxlist->pnext;
        }
        *ppxlist = NULL;
    }

    return pylistNew;
}

/****************************************************************************/

void RECTLISTAddRect(
    PRECTLIST prl,
    int xs,
    int ys,
    int xe,
    int ye)
{
    __GLGENbuffers *buffers = (__GLGENbuffers *)(prl->buffers);
    PYLIST* ppylist;
    PYLIST pylistNew;

    ppylist = &(prl->pylist);
    while ((*ppylist) != NULL) {
        if (ys < (*ppylist)->e) break;
        ppylist  = &((*ppylist)->pnext);
    }

    while ((*ppylist) != NULL) {
        if (ys < (*ppylist)->s) {
            PYLIST pylistNew = YLISTAlloc(buffers);
            if (pylistNew == NULL) {
              OutOfMemory:
                RECTLISTSetEmpty(prl);
                return;
            }

            pylistNew->s = ys;
            pylistNew->e = ye;
            if (!YLISTAddSpan(buffers, pylistNew, xs, xe)) {
                goto OutOfMemory;
            }

            pylistNew->pnext = *ppylist;
            *ppylist = pylistNew;
            ppylist = &((*ppylist)->pnext);

            if (ye <= (*ppylist)->s) {
                return;
            }

            pylistNew->e = (*ppylist)->s;
            ys = (*ppylist)->s;
        } else if (ys == (*ppylist)->s) {
            if (ye >= (*ppylist)->e) {
                if (!YLISTAddSpan(buffers, *ppylist, xs, xe)) {
                    goto OutOfMemory;
                }

                ys = (*ppylist)->e;
                if (ys == ye) return;
                ppylist = &((*ppylist)->pnext);
            } else {
                PYLIST pylistNew = YLISTCopy(buffers, *ppylist);
                if (pylistNew == NULL) {
                    goto OutOfMemory;
                }

                pylistNew->e = ye;
                if (!YLISTAddSpan(buffers, pylistNew, xs, xe)) {
                    goto OutOfMemory;
                }

                (*ppylist)->s = ye;

                pylistNew->pnext = *ppylist;
                *ppylist = pylistNew;

                return;
            }
        } else {
            PYLIST pylistNew = YLISTCopy(buffers, *ppylist);
            if (pylistNew == NULL) {
                goto OutOfMemory;
            }

            pylistNew->e = ys;
            (*ppylist)->s = ys;

            pylistNew->pnext = *ppylist;
            *ppylist = pylistNew;
            ppylist = &((*ppylist)->pnext);
        }
    }

    pylistNew = YLISTAlloc(buffers);
    if (pylistNew == NULL) {
        goto OutOfMemory;
    }

    pylistNew->s = ys;
    pylistNew->e = ye;
    if (!YLISTAddSpan(buffers, pylistNew, xs, xe)) {
        goto OutOfMemory;
    }

    pylistNew->pnext = *ppylist;
    *ppylist = pylistNew;
}

/****************************************************************************/

#ifdef LATER
// these functions are not required in the server implementation

#define MAXRECTS 1024

HRGN RECTLISTCreateRegion(
    PRECTLIST prl)
{
    __GLGENbuffers *buffers = (__GLGENbuffers *)(prl->buffers);
    PYLIST pylist = prl->pylist;
    int irect = 0;
    PRGNDATA prgndata;
    PRECT prc;
    HRGN hrgn;

    prgndata = (PRGNDATA)ALLOC(sizeof(RGNDATAHEADER) + MAXRECTS * sizeof(RECT));
    if (prgndata == NULL) return NULL;

    prc = (PRECT)(prgndata->Buffer);

    while (pylist != NULL) {
        PXLIST pxlist = pylist->pxlist;
        while (pxlist != NULL) {
            prc->left   = pxlist->s;
            prc->right  = pxlist->e;
            prc->top    = pylist->s;
            prc->bottom = pylist->e;
            prc++;
            irect++;
            if (irect == MAXRECTS) {
                //Error("maxrect");
                goto done;
            }

            pxlist = pxlist->pnext;
        }
        pylist = pylist->pnext;
    }

  done:
    prgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
    prgndata->rdh.iType = RDH_RECTANGLES;
    prgndata->rdh.nCount = irect;
    prgndata->rdh.nRgnSize = 0;
    prgndata->rdh.rcBound.left = 0;
    prgndata->rdh.rcBound.right = 4096;
    prgndata->rdh.rcBound.top = 0;
    prgndata->rdh.rcBound.bottom = 4096;

    hrgn = GreExtCreateRegion(NULL, irect * sizeof(RECT) + sizeof(RGNDATAHEADER), prgndata);

    #ifdef LATER
    if (hrgn == NULL) {
        Error1("ExtCreateRegion() Error %d\n", GetLastError());
        Error1("%d rects\n", irect);
        prc = (PRECT)(prgndata->Buffer);
        for (;irect>0; irect--) {
            //printf("(%5d, %5d, %5d, %5d)\n", prc->left, prc->right, prc->top, prc->bottom);
            prc++;
        }
    }
    #endif

    FREE(prgndata);

    return hrgn;
}

/****************************************************************************/

//
// !!! make this do everything in one pass
//

void RECTLISTOr(
    PRECTLIST prl1,
    PRECTLIST prl2)
{
    __GLGENbuffers *buffers = (__GLGENbuffers *)(prl1->buffers);
    PYLIST pylist = prl2->pylist;

    while (pylist != NULL) {
        PXLIST pxlist = pylist->pxlist;

        while (pxlist != NULL) {
            RECTLISTAddRect(prl1, pxlist->s, pylist->s, pxlist->e, pylist->e);
            pxlist = pxlist->pnext;
        }
        pylist = pylist->pnext;
    }
}


/****************************************************************************/

void RECTLISTOrAndClear(
    PRECTLIST prl1,
    PRECTLIST prl2)
{
    __GLGENbuffers *buffers = (__GLGENbuffers *)(prl1->buffers);

    if (RECTLISTIsMax(prl2)) {
        RECTLISTSetMax(prl1);
        RECTLISTSetEmpty(prl2);
    } else {
        if (RECTLISTIsEmpty(prl1)) {
            //
            // If the clear region is empty just swap them
            //
            RECTLISTSwap(prl1, prl2);
        } else {
            //
            // The clear region isn't empty so maximize it.
            //
            RECTLISTSetMax(prl1);
            RECTLISTSetEmpty(prl2);
        }
    }
}

/****************************************************************************/

void RECTLISTSwap(
    PRECTLIST prl1,
    PRECTLIST prl2)
{
    __GLGENbuffers *buffers = (__GLGENbuffers *)(prl1->buffers);
    RECTLIST rlTemp = *prl1;

    *prl1 = *prl2;
    *prl2 = rlTemp;
}
#endif

/****************************************************************************/

void RECTLISTSetEmpty(
    PRECTLIST prl)
{
    __GLGENbuffers *buffers = (__GLGENbuffers *)(prl->buffers);
    PYLIST pylist = prl->pylist;
    PYLIST pylistKill;

    while (pylist != NULL) {
        pylistKill = pylist;
        pylist = pylist->pnext;
        YLISTFree(buffers, pylistKill);
    }

    prl->pylist = NULL;
}

/****************************************************************************/

BOOL RECTLISTIsEmpty(
    PRECTLIST prl)
{
    return (prl->pylist == NULL);
}