/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDLPOLY                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor function handler   */
/*                     PolyLine                                       */
/*                     DisjointLine                                   */
/*                     (DrawLinesInPath via PolyLineWork)             */
/*                                                                    */
/*   Function        = Draws a series of straight lines               */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
/* CHANGE ACTIVITY =                                                  */
/*   DATE      FLAG        APAR   CHANGE DESCRIPTION                  */
/*   --------  ----------  -----  ------------------------------------*/
/*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx                             */
/*   06/02/93              69316  Use clip info from AIxfer instead   */
/*                                of DC.                              */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_DDIMISC
#define INCL_DDIPATHS
#define INCL_GRE_XFORMS
#define INCL_GRE_LINES
#include <eddinclt.h>

#include <edddtypt.h>

#include <eddbextf.h>
#include <eddaextf.h>
#include <eddcextf.h>
#include <eddgextf.h>
#include <eddlextf.h>
#include <eddmextf.h>
#ifdef DCAF                                                               //DCAF
#include <dcafextf.h>                                                     //DCAF
#endif                                                                    //DCAF

#include <eddicone.h>

#include <eddhcone.h>
#include <eddhtype.h>

#include <eddfcone.h>
#include <eddftype.h>

#include <cursor.h>
#include <hwaccess.h>
#include <memman.h>
#ifdef VRAMPTR
#include <eddncach.h>
#endif /* VRAMPTR */

#ifdef _8514
#include <8514.h>

extern VOID DrawPel_8514( ULONG, ULONG );
extern BYTE Conv8514toXGA[];
#endif


/**********************************************************************/
/* Put function definitions here because they should only be used     */
/* from this file because of their assumptions about parameters.      */
/**********************************************************************/
USHORT eddl_IntersectLine(VOID);
ULONG  eddl_Outcode(DevPoint);

VOID eddl_BresenhamOne(VOID);

extern PPFNL            EnginesDispatchTable;

/**********************************************************************/
/* Externals...                                                       */
/* ShadowXGARegs is the software copy memory mapped registers         */
/* VramBase is the physical base of vram.                             */
/* AIxfer is the 'common' storage between DD C code and DD 386        */
/* StaticCoordStore is the memory we have set aside for coordinate    */
/*   conversion                                                       */
/* SPad is the DD scratch pad memory.  This is used to save space on  */
/*   the stack and for passing parameters amongst _tightly_           */
/*   interconnected functions.  In this code file it is cast to       */
/*   the PolyLine definition.                                         */
/* WinToXway is the translation array for mixes.                      */
/* BresSteps is an array of 2D steps disguised as DevPoints used for  */
/*   moving the line position in software line drawing in the 8       */
/*   different octants                                                */
/* PlotSteps is an array with plot-step codes for the hardware in     */
/*   place of the offsets stored in BresSteps (these are stored in    */
/*   the format ready for count to be simply OR'ed into them)         */
/* LinePatternPhys is the base physical address for the line patterns */
/* GPLockData is a structure for locking memory                       */
/* GPUnlockData is a structure for unlocking memory                   */
/**********************************************************************/
#ifndef   _8514
extern MMReg                    ShadowXGARegs;
extern pMMReg                   pXGARegs;
extern pMMReg                   pRealXGARegs;
extern pMMReg                   pXGARegsA;
extern pMMReg                   pXGARegsB;
extern pMMReg                   pXGARegsC;
#else
extern MM8514Reg                Shadow8514Regs;
extern pMM8514Reg               p8514Regs;
extern pMM8514Reg               pXGARegsA;
extern pMM8514Reg               pXGARegsB;
extern pMM8514Reg               pXGARegsC;

#if !(defined(IBMJ) && defined(XGA))                        
extern USHORT                   LinePatternsBitmap[];
#else                                                       
extern ULONG                    LinePatternsBitmap[];
#endif                                                      

#endif
extern ULONG                    VramBase;
extern POLYLINEPB               AIxfer;
extern USHORT                   StaticCoordStore[];
extern PolyLineSP               SPad;
extern BYTE                     WinToXway[];
extern BresStep                 BresSteps[];
extern PlotStep                 PlotSteps[];
extern ULONG                    LinePatternPhys;

extern RGNRECT                  GetClipsControl;
extern ClipRectangle            GetClipsBounds;
extern CURSORDATA               cursor_data;

extern SHORT                    softDrawInUse;
extern ULONG                    LinePatternCur;
extern ULONG                    LinePatternPhys;
extern ULONG                    LinePatternSys;
extern ULONG                    MarkerCur;
extern ULONG                    MarkerPhys;
extern ULONG                    MarkerSys;
extern ULONG                    pCurCacheBasePhy;
extern ULONG                    pSysCacheStartPhy;
extern drawFunctionsTable       softDrawTable;
extern drawFunctionsTable       hardDrawTable;
extern SHORT                    foregroundSession;

extern pDrawFunctionsTable      pDrawFunctions;

/**********************************************************************/
/* eddl_PolyLine                                                      */
/* -------------                                                      */
/* PolyLine draws a series of straight lines starting at the current  */
/* position and passing through all the points in the array supplied  */
/* as an input parameter.                                             */
/*                                                                    */
/* eddl_DisjointLine (eddl_PolyLineDisjoint)                          */
/* -----------------------------------------                          */
/* Draws a series of straight lines between start and end points      */
/* supplied in the points array.                                      */
/*                                                                    */
/* This function supports both calls as a single entry point          */
/**********************************************************************/
DDIENTRY eddl_PolyLine (HDC         hdc,
                        PPOINTL     ArgXYArray,
                        ULONG       ArgNumber,
                        PDC         pdcArg,
                        ULONG       FunN)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG       Result;             /* For returning correlation
                                       result                         */
    PULONG      DriverCoords;       /* Where the points are           */
    BOOL        fAllocCoordSeg;
    POINTL      LocalCurrentPos;

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD);

    /******************************************************************/
    /* Apply the DC command mask to the command bits                  */
    /******************************************************************/
    COMMANDBITS(FunN) &= pdc->DCICommandMask;

#ifndef WE_CLIP_DRAWLINES
    /******************************************************************/
    /* if there are more clip regions than can fit into the cache we  */
    /* can use DrawLinesInPath to perform clipping for us. Therefore  */
    /* return the call to the engine.                                 */
    /******************************************************************/
    if (pdc->DCIEngineClips > CACHED_CLIPS)
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_IGNORE_TIME);
        return EnginesDispatchTable[FunN & 0xff](hdc,
                                                 ArgXYArray,
                                                 ArgNumber,
                                                 pdcArg,
                                                 FunN);
    }
#endif

    /******************************************************************/
    /* If the number of lines to draw is zero then leave immediately  */
    /******************************************************************/
    if (ArgNumber == 0)
    {
        Result = OK;
        goto POLYLINE_OK_EXIT;
    }

    /******************************************************************/
    /* If this is a disjoint line and the number of lines is odd then */
    /* return an error                                                */
    /******************************************************************/
    if ( FUNCTIONIS(FunN, NGreDisjointLines) &&
         (ArgNumber % 2 != 0))
    {
        LogError(PMERR_INV_LENGTH_OR_COUNT);
        goto POLYLINE_ERR_EXIT;
    }

    /******************************************************************/
    /* If COM_PATH or COM_AREA set then pass call back to engine      */
    /******************************************************************/
    if (FunNTest(COM_PATH | COM_AREA))
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_IGNORE_TIME);
        return EnginesDispatchTable[FunN & 0xff](hdc,
                                                 ArgXYArray,
                                                 ArgNumber,
                                                 pdcArg,
                                                 FunN);
    }

    /******************************************************************/
    /* Check if current line attributes supported. A value of anything*/
    /* other than x10000 for the current line width indicates a thick */
    /* line. If COM_DEVICE bit is not set then "thick" lines can be   */
    /* returned to simulations. Otherwise assume thin line.           */
    /******************************************************************/
    if ( !FunNTest(COM_DEVICE)
         && pdc->DCICurLinAts.lbnd.fxWidth != 0x00010000L)
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_IGNORE_TIME);
        return EnginesDispatchTable[FunN & 0xff](hdc,
                                                 ArgXYArray,
                                                 ArgNumber,
                                                 pdcArg,
                                                 FunN);
    }

    /******************************************************************/
    /* Initialise the result variable. This is overwritten if corr-   */
    /* lation is requested and it correlates.                         */
    /******************************************************************/
    Result = OK;

#ifdef OMIT
    /******************************************************************/
    /* This code was just added to try out the technique.             */
    /* It is fatally flawed because it alters the passed data in      */
    /* place.                                                         */
    /* Really we want this code put in the curve drawing part of      */
    /* the engine.                                                    */
    /******************************************************************/

    /******************************************************************/
    /* If we have more than 2 points then batch the lines into the    */
    /* smallest number of longer lines that we can.                   */
    /******************************************************************/
    if (ArgNumber > 2)
    {
        /**************************************************************/
        /* Some local variables just for the batching code.           */
        /**************************************************************/
        ULONG       TrgPoint;
        ULONG       SrcPoint;
        LONG        XDelta;
        LONG        YDelta;
        LONG        XSum;
        LONG        YSum;

        /**************************************************************/
        /* Calculate the initial step of the first line.              */
        /**************************************************************/
        XDelta = ArgXYArray[1].x - ArgXYArray[0].x;
        YDelta = ArgXYArray[1].y - ArgXYArray[0].y;
        XSum = XDelta;
        YSum = YDelta;
        TrgPoint = 1;

        /**************************************************************/
        /* Loop through all the points looking for regular            */
        /* increments.                                                */
        /**************************************************************/
        for (SrcPoint=1; SrcPoint < ArgNumber; SrcPoint++)
        {
            if (((ArgXYArray[SrcPoint+1].x - ArgXYArray[SrcPoint].x)
                                                        == XDelta) &&
                ((ArgXYArray[SrcPoint+1].y - ArgXYArray[SrcPoint].y)
                                                        == YDelta))
            {
                /**************************************************/
                /* This is a regular increment, so just add it    */
                /* to our totals                                  */
                /**************************************************/
                XSum += XDelta;
                YSum += YDelta;
            }
            else
            {
                /**************************************************/
                /* A changed increment, so we end the current     */
                /* line by adding our totals to the start point   */
                /**************************************************/
                ArgXYArray[TrgPoint].x = ArgXYArray[TrgPoint-1].x + XSum;
                ArgXYArray[TrgPoint].y = ArgXYArray[TrgPoint-1].y + YSum;
                /**************************************************/
                /* Move to the next point, and make it the new    */
                /* start initial end point                        */
                /**************************************************/
                TrgPoint++;
                /**************************************************/
                /* Recaluculate the deltas.                       */
                /**************************************************/
                XDelta = ArgXYArray[SrcPoint+1].x - ArgXYArray[SrcPoint].x;
                YDelta = ArgXYArray[SrcPoint+1].y - ArgXYArray[SrcPoint].y;
                XSum = XDelta;
                YSum = YDelta;
            }
        }
        ArgNumber = TrgPoint;
    }
#endif /* OMIT */

    /******************************************************************/
    /* The new scheme of things is as follows:                        */
    /*  For all line related operations                               */
    /*   COM_TRANSFORM set   means coords are passed as WORLD         */
    /*   COM_TRANSFORM clear means coords are passed as SCREEN        */
    /******************************************************************/
    if (FunNTest(COM_TRANSFORM) && !pdc->DCIXFrmSimple)
    {
        /**************************************************************/
        /* We must convert the coordinates to DEVICE coordinates so   */
        /* we need a copy of them.                                    */
        /**************************************************************/
        fAllocCoordSeg = (ArgNumber > MAX_STATIC_COORDS);
        if (fAllocCoordSeg)
        {
            /**********************************************************/
            /* There are too many coordinates for our static storage  */
            /* so we must get some more memory to  use.               */
            /**********************************************************/
            DriverCoords = AllocateMemory( ArgNumber*sizeof(POINTL),
                                           MT_COORDLIST,
                                           MO_PRIVATE );
            if (DriverCoords == NULL)
            {
                /******************************************************/
                /* The allocation has failed.                         */
                /******************************************************/
                /* Defect 55864. Release semaphore before returning */
                ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_IGNORE_TIME);
                return(ERROR_ZERO);
            }
        }
        else
        {
            /**********************************************************/
            /* We can simply use the static storage in our data       */
            /* segment so set pointer to it's start.                  */
            /**********************************************************/
            DriverCoords = (PULONG)StaticCoordStore;
        }

        /**************************************************************/
        /* Copy the given coordinates into our own space              */
        /**************************************************************/
        memcpy( (PVOID)DriverCoords,
                (PVOID)ArgXYArray,
                ArgNumber*sizeof(POINTL) );

        /**************************************************************/
        /* Do the conversion                                          */
        /**************************************************************/
        if ( ! EnginesDispatchTable[NGreConvert & 0xff](
                                                hdc,
                                                CVTC_WORLD,
                                                CVTC_DEVICE,
                                                (PPOINTL)DriverCoords,
                                                ArgNumber,
                                                (ULONG)pdcArg,
                                                NGreConvert        )
           )
        {
            /**********************************************************/
            /* Conversion has failed so free allocated memory if      */
            /* necessary                                              */
            /**********************************************************/
            if (fAllocCoordSeg)
            {
                FreeMemory(DriverCoords);
            }
            goto POLYLINE_ERR_EXIT;
        }

        /**************************************************************/
        /* We now have coords as DEVICE coord                         */
        /**************************************************************/
    }
    else /* no transform needed */
    {
        /**************************************************************/
        /* We don't convert the coordinates so we can use the         */
        /* original parameters.                                       */
        /**************************************************************/
        DriverCoords = (PULONG)ArgXYArray;
        fAllocCoordSeg = FALSE;
    }

    if (FunNTest(COM_CORRELATE) && (pdc->DCICorrInvalid))
    {
        /**************************************************************/
        /* Will be doing correlation so get the correlation rectangles*/
        /* up to date                                                 */
        /**************************************************************/
        if (! eddg_ClipPickWindow())
        {
            goto POLYLINE_ERR_EXIT;
        }
    }

    /******************************************************************/
    /* Call the work routine to actually output the lines.            */
    /*                                                                */
    /* NB. If COM_TRANSFORM is set we converted from WORLD to DEVICE  */
    /*     if it was clear then we were passed SCREEN                 */
    /*                                                                */
    /* Thus the passed FunN is needed to distinguish between DEVICE   */
    /* and SCREEN.                                                    */
    /******************************************************************/
    Result = eddl_PolyLineWork(DriverCoords,
                               ArgNumber,
                               FunN );

    /******************************************************************/
    /* Reset bit 0 of the style high word, to indicate figure not     */
    /* starting                                                       */
    /******************************************************************/
    pdc->StyleNumber &= 0xFFFEFFFF;

    /******************************************************************/
    /* Update the current position before leaving.  Do it for both    */
    /* WORLD and HW coordinates                                       */
    /******************************************************************/
    if (FunNTest(COM_TRANSFORM))
    {
        /**************************************************************/
        /* We were passed WORLD coords, so our DriverCoords are       */
        /* currently DEVICE                                           */
        /**************************************************************/
        pdc->DCICurrPosWorld = ArgXYArray[ArgNumber-1];

        pdc->DCICurrPosAI.X = pdc->DCIOrigin.X +
                        (USHORT)(DriverCoords[(ArgNumber-1)*2]);
        pdc->DCICurrPosAI.Y = pdc->DCIConvFactor -
                      (USHORT)(DriverCoords[(ArgNumber-1)*2+1]);
    }
    else
    {
        /**************************************************************/
        /* Do the SCREEN to WORLD conversion.                         */
        /**************************************************************/
        /**************************************************************/
        /* The given point is in SCREEN coords.  First we convert it  */
        /* to DEVICE coords.                                          */
        /**************************************************************/
        LocalCurrentPos.x = DriverCoords[(ArgNumber-1)*2] -
                                                       pdc->DCIOrigin.X;
        LocalCurrentPos.y = DriverCoords[(ArgNumber-1)*2+1] -
                                                       pdc->DCIOrigin.Y;

        /**************************************************************/
        /* Now we do any necessary DEVICE to WORLD transformation.    */
        /**************************************************************/
        if ( !pdc->DCIXFrmSimple )
        {
            /**********************************************************/
            /* Call the engine convert function directly (for         */
            /* performance reasons).                                  */
            /**********************************************************/
            if ( OK != EnginesDispatchTable[NGreConvert & 0xff](
                                          hdc,
                                          CVTC_DEVICE,
                                          CVTC_WORLD,
                                          &LocalCurrentPos,
                                          1,
                                          FNULL,
                                          NGreConvert) )
            {
                /******************************************************/
                /* The conversion failed so log an error.             */
                /******************************************************/
                LogError(PMERR_COORDINATE_OVERFLOW);
                goto POLYLINE_ERR_EXIT;
            }
        }

        /**************************************************************/
        /* Having got the WORLD current position, store it back in    */
        /* the DC instance.                                           */
        /**************************************************************/
        pdc->DCICurrPosWorld = LocalCurrentPos;

        /**************************************************************/
        /* We were passed SCREEN coords, so just flip the Y coord     */
        /* to give us the current HW position to store.               */
        /**************************************************************/
        pdc->DCICurrPosAI.X = (USHORT)(DriverCoords[(ArgNumber-1)*2]);
        pdc->DCICurrPosAI.Y = pdc->DCIBoundingClip[1].Y -
                          (USHORT)(DriverCoords[(ArgNumber-1)*2+1]);
    }

    /******************************************************************/
    /* Check to see if we should deallocate the memory for the        */
    /* coordinates                                                    */
    /******************************************************************/
    if (fAllocCoordSeg)
    {
        /**************************************************************/
        /* Need to free the allocated memory                          */
        /**************************************************************/
        FreeMemory(DriverCoords);
    }

POLYLINE_OK_EXIT:
    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(Result);

POLYLINE_ERR_EXIT:
    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(ERROR_ZERO);

}




ClipRectangle   SingleClipRect = {0, 0, 0, 0, 0, 0, 0, 0};




/**********************************************************************/
/* This is the polyline workhorse routine.                            */
/* It is used by eddl_PolyLine ('eddl_DisjointLine') and              */
/* eddl_DrawLinesInPath                                               */
/*                                                                    */
/* NB. The COM_TRANSFORM bit here indicates                           */
/*      if set coords are DEVICE                                      */
/*      if clear, coords are SCREEN                                   */
/*                                                                    */
/* We believe we will only ever get SCREEN coords when called to do   */
/* a drawlinesinpath - ie COM_TRANSFORM will be clear.                */
/**********************************************************************/
USHORT eddl_PolyLineWork(PULONG     DriverCoords,
                         ULONG      ArgNumber,
                         ULONG      FunN)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG       Result = OK;        /* For correlation                */
    ULONG       Point;              /* Loop control                   */
    ULONG       i;                  /* Loop control                   */
    DevPoint    CorrStart;          /* For correlation...             */
    DevPoint    CorrEnd;            /*                                */
    ULONG       LoopCount;          /* Loop count for bounds          */


    if (  FUNCTIONIS(FunN, NGreDisjointLines) )
    {
        /**************************************************************/
        /* This is a disjoint lines call -                            */
        /* Our polyline routines assume that the start position is in */
        /* DCICurrPosAI so set up DCICurrPosAI                        */
        /* As we have just set up the start postion increase          */
        /* DriverCoords so it points to the second point in the array */
        /* (the end of the first line)                                */
        /* Reset the line pattern postion                             */
        /* Set the .usCallType flag                                   */
        /**************************************************************/
        if (FunNTest(COM_TRANSFORM))
        {
            /**********************************************************/
            /* Coords are DEVICE                                      */
            /**********************************************************/
            pdc->DCICurrPosAI.X = (SHORT)DriverCoords[0] + pdc->DCIOrigin.X;
            pdc->DCICurrPosAI.Y =
                             pdc->DCIConvFactor - (SHORT)DriverCoords[1];
        }
        else
        {
            /**********************************************************/
            /* Passed coords are SCREEN                               */
            /**********************************************************/
            pdc->DCICurrPosAI.X = DriverCoords[0];
            pdc->DCICurrPosAI.Y = pdc->DCIBoundingClip[1].Y -
                                                        DriverCoords[1];
        }
        DriverCoords += 2;
        pdc->DCILinePatCnt = 0;
        AIxfer.usCallType = DISJOINT_CALL;
    }
    else
    {
        /**************************************************************/
        /* This is a polyline call -                                  */
        /* This is what the routine was written for so it works       */
        /* unchanged                                                  */
        /**************************************************************/
        AIxfer.usCallType = POLYLINE_CALL;
    }

    /******************************************************************/
    /* We need the bounds if                                          */
    /*   - software cursor and this is the screen (for exclusion)     */
    /*   - the bounds bits are set in FunN                            */
    /*   - we have more clip regions than will fit in the cache and   */
    /*     we are not processing a DrawLinesInPath call (which is     */
    /*     preclipped anyway)                                         */
    /******************************************************************/
    if (FunNTest(COM_BOUND | COM_ALT_BOUND) ||
#ifdef DCAF                                                               //DCAF
        DCAFBoundsRequired(FunN) ||                                       //DCAF
#endif                                                                    //DCAF
        ( (cursor_data.cursor_status & CURSOR_SOFTWARE ) &&
                        (pdc->DCIBitmapType == BITMAP_IS_SCREEN) ) ||
        (pdc->DCIEngineClips > CACHED_CLIPS))
    {
        /**************************************************************/
        /* Initialize bounds...                                       */
        /* The type of coords depends on the COM_TRANSFORM flag       */
        /*   - if set they are DEVICE                                 */
        /*   - if clear they are SCREEN                               */
        /**************************************************************/
        if (FunNTest(COM_TRANSFORM))
        {
            /**********************************************************/
            /* The coords are DEVICE - Initialise bounds to current   */
            /* position in device coordinates.                        */
            /**********************************************************/
            SPad.PLineBounds[0].X = SPad.PLineBounds[1].X =
                          pdc->DCICurrPosAI.X - pdc->DCIOrigin.X;
            SPad.PLineBounds[0].Y = SPad.PLineBounds[1].Y =
                        pdc->DCIConvFactor - pdc->DCICurrPosAI.Y;
        }
        else
        {
            /**********************************************************/
            /* The coords are SCREEN - Initialise bounds to current   */
            /* position in screen coordinates.                        */
            /**********************************************************/
            SPad.PLineBounds[0].X = SPad.PLineBounds[1].X =
                                                pdc->DCICurrPosAI.X;
            SPad.PLineBounds[0].Y = SPad.PLineBounds[1].Y =
                 pdc->DCIBoundingClip[1].Y - pdc->DCICurrPosAI.Y;
        }

        /**************************************************************/
        /* We want to loop through one less point for disjoint lines  */
        /**************************************************************/
        if ( FUNCTIONIS(FunN, NGreDisjointLines))
        {
            LoopCount = ArgNumber - 1;
        }
        else
        {
            LoopCount = ArgNumber;
        }

        /**************************************************************/
        /* Step through the array a point at a time accumulating      */
        /* bounds in SPad.PLineBounds.                                */
        /**************************************************************/
        for ( Point=0; Point < LoopCount; Point++ )
        {
            register SHORT CoordX;
            register SHORT CoordY;

            /**********************************************************/
            /* Get the coordinates first.                             */
            /**********************************************************/
            CoordX = (USHORT)(DriverCoords[Point*2]);
            CoordY = (USHORT)(DriverCoords[Point*2+1]);

            /**********************************************************/
            /* Now accumulate the bounds.                             */
            /**********************************************************/
            if (CoordX < SPad.PLineBounds[0].X)
            {
                SPad.PLineBounds[0].X = CoordX;
            }
            else if (CoordX > SPad.PLineBounds[1].X)
            {
                SPad.PLineBounds[1].X = CoordX;
            }

            if (CoordY < SPad.PLineBounds[0].Y)
            {
                SPad.PLineBounds[0].Y= CoordY;
            }
            else if (CoordY > SPad.PLineBounds[1].Y)
            {
                SPad.PLineBounds[1].Y = CoordY;
            }
        }

        /**************************************************************/
        /* We have just accumulated bounds in either DEVICE or SCREEN */
        /* coords.                                                    */
        /* The type of coords depends on the COM_TRANSFORM flag       */
        /*   - if set they are DEVICE                                 */
        /*   - if clear they are SCREEN                               */
        /**************************************************************/
        if (!FunNTest(COM_TRANSFORM))
        {
            /**********************************************************/
            /* COM_TRANSFORM clear, so these are SCREEN coords        */
            /**********************************************************/
            /* We will convert these bounds to device coordinates by  */
            /* applying the DCOrigin to them - this means we can use  */
            /* them correctly later in WalkTheBitmap                  */
            /**********************************************************/
            SPad.PLineBounds[0].X -= pdc->DCIOrigin.X;
            SPad.PLineBounds[1].X -= pdc->DCIOrigin.X;
            SPad.PLineBounds[0].Y -= pdc->DCIOrigin.Y;
            SPad.PLineBounds[1].Y -= pdc->DCIOrigin.Y;
        }

#ifdef OMIT
        /**************************************************************/
        /* This is the old code from here                             */
        /*   - the code was       but the comment is useful so I've   */
        /*     left it in for reference !                             */
        /**************************************************************/
        if ( FUNCTIONIS(FunN, NGreDrawLinesInPath) )
        {
            /******************************************************/
            /* This is part of a DrawLinesInPath function so the  */
            /* bounds we have accumulated are actually in         */
            /* screen coordinates.                                */
            /* _FLAME ON_                                         */
            /* The driver gets DLIP calls with COM_TRANSFORM set  */
            /* and a transform which is an identity _but_ the     */
            /* coordinates passed are screen coordinates.  This   */
            /* would be okay because we could put them through    */
            /* the transform and they would come out the other    */
            /* side unchanged.  However, if we were to put them   */
            /* through the transform we should assume that the    */
            /* result is in device coordinates (because there     */
            /* isn't a transform from world to screen) and so     */
            /* when we used these coordinates we should apply the */
            /* DC Origin.  The DC Origin in these cases may be    */
            /* non-zero so if we applied it to the coordinates we */
            /* would get the       result.  The driver avoids     */
            /* this by ignoring the COM_TRANSFORM bit on DLIP     */
            /* calls and assuming the coordinates are in screen   */
            /* coordinates.                                       */
            /* _FLAME OFF_                                        */
            /* We will convert these bounds to device coordinates */
            /* by applying the DCOrigin to them - this means we   */
            /* can use them correctly later in WalkTheBitmap      */
            /******************************************************/
            SPad.PLineBounds[0].X -= pdc->DCIOrigin.X;
            SPad.PLineBounds[1].X -= pdc->DCIOrigin.X;
            SPad.PLineBounds[0].Y -= pdc->DCIOrigin.Y;
            SPad.PLineBounds[1].Y -= pdc->DCIOrigin.Y;
        }
#endif /* OMIT */

        /**************************************************************/
        /* If the engine asked for bounding use our local bounds to   */
        /* update the bounds rectangle.                               */
        /**************************************************************/
        if (FunNTest(COM_BOUND | COM_ALT_BOUND))
        {
            /**********************************************************/
            /* Now go ahead and add the bounds                        */
            /**********************************************************/
            eddg_AddBounds ((pDevRect)SPad.PLineBounds,
                            FunN,
                            COORD_DEVICE_WORD);
        }

#ifdef DCAF                                                               //DCAF
        /**************************************************************/  //DCAF
        /* Accumulate DCAF screen bounds if required                  */  //DCAF
        /**************************************************************/  //DCAF
        if ( DCAFBoundsRequired(FunN) )                                   //DCAF
        {                                                                 //DCAF
            AccumulateScreenBoundsThroughClips((pDevRect)SPad.PLineBounds,//DCAF
                                               COORD_DEVICE_WORD );       //DCAF
        }                                                                 //DCAF
#endif                                                                    //DCAF

    }

    /******************************************************************/
    /* If correlate bit is set then we will have to do some           */
    /* correlation..                                                  */
    /******************************************************************/
    if ( FunNTest(COM_CORRELATE) && pdc->DCICorrNum )
    {
        /**************************************************************/
        /* If we have been called from DrawLinesInPath we will have a */
        /* single line to correlate on. Do it seperately              */
        /**************************************************************/
        if (  FUNCTIONIS(FunN, NGreDrawLinesInPath) )
        {
            /**********************************************************/
            /* Get end points of the line. Driver coords are SCREEN   */
            /* Correlation is done on AI coordinates                  */
            /**********************************************************/
            CorrStart.X = (USHORT)(DriverCoords[0]);
            CorrStart.Y = (USHORT)((ULONG)pdc->DCISelListEntry->Info.Height -
                                    1 - DriverCoords[1]);
            CorrEnd.X = pdc->DCICurrPosAI.X;
            CorrEnd.Y = pdc->DCICurrPosAI.Y;

            /**********************************************************/
            /* Do the deed..                                          */
            /**********************************************************/
            Result = eddg_CheckLineCorrelation((pDevPoint)&CorrStart,
                                               (pDevPoint)&CorrEnd);
        }
        else
        {
            /**********************************************************/
            /* First get the start position.. (just in case)          */
            /**********************************************************/
            CorrEnd.X = pdc->DCICurrPosAI.X;
            CorrEnd.Y = pdc->DCICurrPosAI.Y;

            /**********************************************************/
            /* Now do all the vectors (or until we get a correlation) */
            /* If this is polyline (.usCallType == 1) then step       */
            /* through one point at a time because each point equals  */
            /* one line If this is a disjoint line (.usCallType == 2) */
            /* then step through two points at a time because two     */
            /* points equal one line                                  */
            /**********************************************************/
            for ( i = AIxfer.usCallType - 1;
                  (i < ArgNumber) && (Result == OK);
                  i += AIxfer.usCallType )
            {
                /******************************************************/
                /* Different processing depending on .usCallType      */
                /******************************************************/
                if (AIxfer.usCallType == DISJOINT_CALL)
                {
                    /**************************************************/
                    /* Need to get start point for line as it is not  */
                    /* the same as the end point of the last line     */
                    /* As this is disjoint line i will start from 1 so*/
                    /* the minuses in the array access are OK         */
                    /* Correlation is done on AI coordinates          */
                    /**************************************************/
                    if (FunNTest(COM_TRANSFORM))
                    {
                        /**********************************************/
                        /* Coords are DEVICE                          */
                        /**********************************************/
                        CorrStart.X = (USHORT)(DriverCoords[i*2-2]) +
                                                       pdc->DCIOrigin.X;
                        CorrStart.Y = pdc->DCIConvFactor -
                                          (USHORT)(DriverCoords[i*2-1]);
                    }
                    else
                    {
                        /**********************************************/
                        /* Coords are SCREEN                          */
                        /**********************************************/
                        CorrStart.X = (USHORT)(DriverCoords[i*2-2]);
                        CorrStart.Y = pdc->DCIBoundingClip[1].Y -
                                          (USHORT)(DriverCoords[i*2-1]);
                    }
                }
                else
                {
                    /**************************************************/
                    /* Start point will be same as the last endpoint  */
                    /**************************************************/
                    CorrStart = CorrEnd;
                }

                /******************************************************/
                /* Get end point of this line                         */
                /* Correlation is done on AI coordinates              */
                /******************************************************/
                if (FunNTest(COM_TRANSFORM))
                {
                    /**************************************************/
                    /* Coords are DEVICE.                             */
                    /**************************************************/
                    CorrEnd.X =
                           (USHORT)(DriverCoords[i*2]) + pdc->DCIOrigin.X;
                    CorrEnd.Y =
                       pdc->DCIConvFactor - (USHORT)(DriverCoords[i*2+1]);
                }
                else
                {
                    /**************************************************/
                    /* Coords are SCREEN.                             */
                    /**************************************************/
                    CorrEnd.X = (USHORT)(DriverCoords[i*2]);
                    CorrEnd.Y = pdc->DCIBoundingClip[1].Y -
                                          (USHORT)(DriverCoords[i*2+1]);
                }

                /******************************************************/
                /* Do the deed..                                      */
                /******************************************************/
                Result = eddg_CheckLineCorrelation(
                                           (pDevPoint)&CorrStart,
                                           (pDevPoint)&CorrEnd);
            }
        }
    }

    /******************************************************************/
    /* Check there is a currently selected bitmap (we have done       */
    /* bounds and correlation)                                        */
    /******************************************************************/
    if (pdc->DCIBitmapType == BITMAP_NOT_SELECTED )
    {
        /**************************************************************/
        /* It is not an error to have no selected bitmap as long as   */
        /* COM_DRAW is off - otherwise it is an error                 */
        /**************************************************************/
        if (FunNTest(COM_DRAW))
        {
            LogError(PMERR_BITMAP_NOT_SELECTED);
            Result = ERROR_ZERO;
        }

        goto POLYLINEWORK_EXIT;
    }

    /******************************************************************/
    /* Now, if COM_DRAW is on, do the serious business...             */
    /******************************************************************/
    if (FunNTest(COM_DRAW))
    {

        /**************************************************************/
        /* Now it is time to set the drawing mode correctly..         */
        /**************************************************************/
        if (pdc->DCIBitmapType == BITMAP_IS_SCREEN)
        {
            SetDrawModeHard;
        }
        else
        {
            SetDrawModeSoft;
        }

        /**************************************************************/
        /* Start with a default setting of the Pixel Operations Value */
        /* this may be altered either in the c code or later in the   */
        /* assembler to take account of say non-solid patterns        */
        /**************************************************************/
        AIxfer.ulPixelOp = POLYLINE_DEFAULT;

        if ( (!(pdc->StyleNumber & 0x00010000)) &&
             (AIxfer.usCallType == POLYLINE_CALL) )
        {
            /**********************************************************/
            /* Figure not starting so set draw mode to omit first pel */
            /* This means the current position was the result of some */
            /* other drawing operation.                               */
            /* Also the line pattern count will refer to the next pel */
            /* to be drawn but as we're going to draw the first pel   */
            /* null we need to decrease it by one so that the first   */
            /* pel we draw is from the correct position in the        */
            /* pattern.                                               */
            /* Note that we always draw the first pel in Disjoint     */
            /* Lines calls.                                           */
            /**********************************************************/
            AIxfer.ulPixelOp &= ~DRAW_MODE_MASK;
            AIxfer.ulPixelOp |= DRAW_MODE_NO_FIRST_PEL;
#if !(defined(IBMJ) && defined(XGA))                        
            pdc->DCILinePatCnt = (USHORT)(((ULONG)pdc->DCILinePatCnt-1) & 0x0F);
#else                                                       
            pdc->DCILinePatCnt = (USHORT)(((ULONG)pdc->DCILinePatCnt-1) & 0x1F);
#endif                                                      
        }

        /**************************************************************/
        /* before we start to use the hardware, if the cursor is      */
        /* colour then the cursor my need to be                       */
        /* excluded and further drawing on the mouse interrupt thread */
        /* must be disabled                                           */
        /**************************************************************/
        if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
        {
           eddm_ExcludeCursor(SPad.PLineBounds, COORD_DEVICE_WORD);
        }

        /**************************************************************/
        /* Now set colours and mixes.                                 */
        /**************************************************************/
#ifndef _8514
        ShadowXGARegs.FgCol = (USHORT)pdc->DCILineColatts.ForeColor;
        ShadowXGARegs.FgMix = WinToXway[pdc->DCICurLinAts.lbnd.usMixMode];

#ifdef LINESBG
        /**************************************************************/
        /* Now set background colours and mixes.                      */
        /**************************************************************/
        ShadowXGARegs.BgCol = (USHORT)pdc->DCILineColatts.BackColor;
        ShadowXGARegs.BgMix = WinToXway[pdc->DCICurLinAts.lbnd.usBackMixMode];
#else /* LINESBG */
        ShadowXGARegs.BgMix = HWMIX_DEST;
#endif /* LINESBG */
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;

#else  /* 8514 */

        #ifndef   BPP24
        Shadow8514Regs.Color_1 = (USHORT)pdc->DCILineColatts.ForeColor;
        #else
        Shadow8514Regs.Color_1 = pdc->DCILineColatts.ForeColor;
        #endif
        Shadow8514Regs.Function_1.Mix = WinToXway[pdc->DCICurLinAts.lbnd.usMixMode];
        Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COL1;

#ifdef LINESBG
        /**************************************************************/
        /* Now set background colours and mixes.                      */
        /**************************************************************/
        #ifndef   BPP24
        Shadow8514Regs.Color_0 = (USHORT)pdc->DCILineColatts.BackColor;
        #else
        Shadow8514Regs.Color_0 = pdc->DCILineColatts.BackColor;
        #endif
        Shadow8514Regs.Function_0.Mix = WinToXway[pdc->DCICurLinAts.lbnd.usBackMixMode];
#else /* LINESBG */
        Shadow8514Regs.Function_0.Mix = FUNC_D;
#endif /* LINESBG */
        Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COL0;
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;

        /**************************************************************/
        /* If we're drawing to a bitmap, change the rop number to one */
        /* that the MESS code understands.                            */
        /**************************************************************/
        if ( softDrawInUse )
        {
            Shadow8514Regs.Function_1.Mix = Conv8514toXGA[Shadow8514Regs.Function_1.Mix];
            Shadow8514Regs.Function_0.Mix = Conv8514toXGA[Shadow8514Regs.Function_0.Mix];
        }

#endif

        TransferShadowRegisters(TSR_COLOUR_MIX);

        /**************************************************************/
        /* Set up the pattern information. Note that we do not set up */
        /* the line pattern count for DrawLinesInPath since it is set */
        /* up, for each lime, by the calling routine                  */
        /**************************************************************/
        AIxfer.usPatType = pdc->DCICurLinAts.lbnd.usType;

        /**************************************************************/
        /* Set up the clip rectangle parameter                        */
        /**************************************************************/
        if ( FUNCTIONIS(FunN, NGreDrawLinesInPath) )
        {
            /**********************************************************/
            /* Set these up now - they will not be changed throughout */
            /* drawing this line even if we go through WalkTheBitmap  */
            /**********************************************************/
            AIxfer.pClipRects = &SingleClipRect;
            AIxfer.cClipRects = 1;
        }
        else
        {
            AIxfer.pClipRects = pdc->DCIClipRects;
            AIxfer.usPatPos = pdc->DCILinePatCnt;
        }

        /**************************************************************/
        /* Set up the start point and the number and address of the   */
        /* points                                                     */
        /* The number of points is more accurately the number of lines*/
        /* and therefore we must divide ArgNumber by 2 if this is a   */
        /* disjoint line                                              */
        /**************************************************************/
        AIxfer.ptsFirstPos.x = pdc->DCICurrPosAI.X;
        AIxfer.ptsFirstPos.y = pdc->DCICurrPosAI.Y;
        AIxfer.cPoints = ArgNumber / AIxfer.usCallType;
        AIxfer.pPoints = DriverCoords;

        /**************************************************************/
        /* Set up the device offsets - dependant on the COM_TRANSFORM */
        /* bit                                                        */
        /**************************************************************/
        if (FunNTest(COM_TRANSFORM))
        {
            /**********************************************************/
            /* The transform bit is set so the coordinates have been  */
            /* converted from WORLD to DEVICE and we need to allow for*/
            /* the DC origin                                          */
            /**********************************************************/
            AIxfer.ptsDevOffsets.x = pdc->DCIOrigin.X;
            AIxfer.ptsDevOffsets.y = pdc->DCIConvFactor;
        }
        else
        {
            /**********************************************************/
            /* The transform bit is not set so the coordinates are in */
            /* SCREEN coords - simply flip the y coordinate           */
            /**********************************************************/
            AIxfer.ptsDevOffsets.x = 0;
            AIxfer.ptsDevOffsets.y = pdc->DCIBoundingClip[1].Y;
        }

        /**************************************************************/
        /* Now start to split the polyline into the different cases   */
        /* which we handle it as.                                     */
        /**************************************************************/

        /**************************************************************/
        /* Note that some lines cannot be drawn directly by the       */
        /* hardware.  These exceptions are lines which are longer     */
        /* than 4096 pels and lines which cross the guard area        */
        /* boundary (although lines which fall into the second        */
        /* category and not the first may be drawn partially in       */
        /* hardware ie once the line has been 'led' into the guard    */
        /* area by software - but we don't do this ).  When writing   */
        /* the code the assumption has been made that lines which CAN */
        /* be drawn in hardware are a) the majority of cases and b)   */
        /* the most critical path.  So the code is organised so that  */
        /* the checking for these problem cases interferes as little  */
        /* as possible with the critical path of drawing using the    */
        /* hardware.                                                  */
        /**************************************************************/

        /**********************************************************/
        /* There is only one destination bitmap.  It will either  */
        /* be the screen or in PS/2 memory.                       */
        /**********************************************************/

        /**********************************************************/
        /* There is only one destination bitmap so give the header*/
        /* to PMLINES.                                            */
        /**********************************************************/
        AIxfer.pbmhDest = pdc->DCISelListEntry;

        /**********************************************************/
        /* Set up the bitmap dimensions for BresenhamOne just in  */
        /* case it has to be called.                              */
        /**********************************************************/
        SPad.BitmapSize.X = pdc->DCISelListEntry->Info.Width;
        SPad.BitmapSize.Y = pdc->DCISelListEntry->Info.Height;


        if ( FUNCTIONIS(FunN, NGreDrawLinesInPath) )
        {
            AIxfer.cClipRects = 1;
            /**************************************************/
            /* Now call eddh_PMLINES.                         */
            /* This assembler function will draw all the      */
            /* vectors into all the cached clip rectangles.   */
            /* It also handles open/closed polylines.         */
            /* If it finds a vector which it cannot draw in   */
            /* hardware then it will call the software        */
            /* emulation routine to do this.                  */
            /* Assumptions made by PMLINES on entry..         */
            /*   All the parameters in AIxfer are set up      */
            /*     correctly                                  */
            /*   The clip rectangles are in DS:               */
            /*   The hardware is ready                        */
            /**************************************************/
            (*(*pDrawFunctions)[index_PMLINES])();
        }
        else
        {
            /**********************************************************/
            /* Set the area for which we want the clip regions        */
            /**********************************************************/
            /**********************************************************/
            /* If there are less than 4 clip rectangles, ensure that  */
            /* the bounding clip rectangle is the size of the bitmap. */
            /* This ensures that we get all clip rectangles into the  */
            /* cache. Otherwise we can optimise the clips so we only  */
            /* get those which intersect the bounds.                  */
            /* note: bounds are only calculated in certain cases (one */
            /*       of which is if there are more clip rectangles    */
            /*       than will fit in the cache                       */
            /**********************************************************/
            /**********************************************************/
            /* MEBTEMP:                                               */
            /* I assume that this TRUE was added as an experiment!    */
            /* I have not got time to check out what happens if it    */
            /* is removed, so I'll leave it in place for now.         */
            /**********************************************************/
            if (TRUE || pdc->DCIEngineClips <= CACHED_CLIPS)
            {
                GetClipsBounds.X0 = pdc->DCIBoundingClip[0].X;
                GetClipsBounds.X1 = pdc->DCIBoundingClip[1].X + (USHORT)1;
                GetClipsBounds.Y0 = pdc->DCIBoundingClip[0].Y;
                GetClipsBounds.Y1 = pdc->DCIBoundingClip[1].Y + (USHORT)1;
            }
            else
            {
                /******************************************************/
                /* If the bounds are outside the drawing area then    */
                /* exit.                                              */
                /* This check must be done otherwise the bounding     */
                /* clip rectangle will become badly ordered and       */
                /* result in a firewall when GetClipRectangles is     */
                /* called. This check is not put in the mainline code */
                /* for performance reasons                            */
                /******************************************************/
                if ((SPad.PLineBounds[0].X >
                                        pdc->DCIBoundingClip[1].X) ||
                    (SPad.PLineBounds[1].X < 0) ||
                    (SPad.PLineBounds[0].Y >
                                        pdc->DCIBoundingClip[1].Y) ||
                    (SPad.PLineBounds[1].Y < 0))
                {
                    goto POLYLINEWORK_EXIT;
                }

                /******************************************************/
                /* Set the clip bounds to the intersection of the     */
                /* bounds with the bitmap. The bounding rectangle for */
                /* the clips is in device coordinates.                */
                /******************************************************/
                GetClipsBounds.X0 = max (SPad.PLineBounds[0].X, (USHORT)0);
                GetClipsBounds.X1 = min ((SPad.PLineBounds[1].X + (USHORT)1),
                                    (pdc->DCIBoundingClip[1].X + (USHORT)1));
                GetClipsBounds.Y0 = max ((pdc->DCIConvFactor +
                       pdc->DCIOrigin.Y - SPad.PLineBounds[1].Y), (USHORT)0);
                GetClipsBounds.Y1 = min ((pdc->DCIConvFactor + (USHORT)1 +
                           pdc->DCIOrigin.Y - SPad.PLineBounds[0].Y),
                                    (pdc->DCIBoundingClip[1].Y + (USHORT)1));
            }

            /**********************************************************/
            /* do the appropriate drawing to all clip regions         */
            /**********************************************************/
            GetClipsControl.ircStart = 1;
            do /* for each rectangle comprising the clip region */
            {
                /******************************************************/
                /* set the GetClips control structure number of       */
                /* rectangles returned to zero so that we will exit   */
                /* loop if all rectangles processed                   */
                /******************************************************/
                GetClipsControl.crcReturned = 0;

                /******************************************************/
                /* if the total number of clips comprising the region */
                /* exceed the size of the dc cache or                 */
                /* NotifyClipChange was called then get the cache     */
                /* updated from engine                                */
                /******************************************************/
                if ( (pdc->DCIEngineClips > CACHED_CLIPS) ||
                                                   pdc->ClipChanged )
                {
                    edda_GetClipRectangles();
                    /**************************************************/
                    /* reset the start rectangle for next iteration   */
                    /**************************************************/
                    GetClipsControl.ircStart +=
                                            GetClipsControl.crcReturned;

                }

                /******************************************************/
                /* if there are now some cached clip rectangles then  */
                /* call the low level function which can cope with    */
                /* drawing the lines to all the cached clip           */
                /* rectangles                                         */
                /******************************************************/
                if (pdc->DCIClipNum)
                {
                    AIxfer.cClipRects = pdc->DCIClipNum;
                    /**************************************************/
                    /* Now call eddh_PMLINES.  This assembler         */
                    /* function will draw all the vectors into all    */
                    /* the cached clip rectangles.  It also handles   */
                    /* open/closed polylines.  If it finds a vector   */
                    /* which it cannot draw in hardware then it will  */
                    /* call the software emulation routine to do      */
                    /* this.  Assumptions made by PMLINES on entry..  */
                    /* All the parameters in AIxfer are set up        */
                    /* correctly The clip rectangles are in DS: The   */
                    /* hardware is ready                              */
                    /**************************************************/
                    (*(*pDrawFunctions)[index_PMLINES])();
                }

            } while ( GetClipsControl.crcReturned &&
                  (GetClipsControl.ircStart <= pdc->DCIEngineClips));
        }

        /**************************************************************/
        /* Get the pattern position for our pdc.  Fetching it from    */
        /* here (and updating this throughout the operation) means we */
        /* don't have to wait for the hardware to finish the last     */
        /* line.  For disjoint lines this pattern position is the     */
        /* position after the last line is drawn but the pattern      */
        /* position has been reset at the start of every line         */
        /*                                                            */
        /**************************************************************/
        pdc->DCILinePatCnt = AIxfer.usPatEnd;

#ifdef VRAMPTR
        /**************************************************************/
        /* If the target bitmap is cached then evict it since it has  */
        /* been drawn to.                                             */
        /**************************************************************/
        if ( BITMAP_IS_CACHED(AIxfer.pbmhDest) )
        {
          evict_cached_bitmap(AIxfer.pbmhDest->bm_cache_slot);
        }
#endif /* VRAMPTR */
    }

    /******************************************************************/
    /* Return the result of the correlation.                          */
    /******************************************************************/

POLYLINEWORK_EXIT:
    /******************************************************************/
    /* If the cursor is colour then cursor drawing will have been     */
    /* disabled while drawborder used the hardware. If this is the    */
    /* case then the cursor EXCLUDED status will be set and we should */
    /* set it up to do a redraw on the next MoveCursor (CheckCursor)  */
    /******************************************************************/
    reenable_cursor();



    return (Result);
}

/**********************************************************************/
/* eddl_BresenhamOne                                                  */
/* -----------------                                                  */
/* This function is for use ONLY within eddlpoly as it has parameters */
/* passed by mutual understanding within this code file!!!            */
/* It draws a line between (Spad.startpoint.x, SPad.startpoint.y) and */
/* (Spad.endpoint.x, SPad.endpoint.y).                                */
/* This function must be a simulation of the hardware drawing and the */
/* code in PMLINES which draws these lines so that its use is         */
/* transparent to PMLINES.  PMLINES will be responsible for ensuring  */
/* no meaningful register values are corrupted but this code must     */
/* ensure that the AIxfer parameters, the hardware etc is left        */
/* as if the line had been drawn by hardware.  This function is also  */
/* responsible for trying to avoid drawing the line at all and so it  */
/* performs intersections on the line and the destination and clip    */
/* rectangles to make sure we have to draw it.                        */
/**********************************************************************/

/**************************************************************/
/* 8514 Notes                                                 */
/*                                                            */
/* The hardware patterns on the 8514/A are horizontally       */
/* aligned and do not allow for the proper representation of  */
/* diagonal or vertical styled lines.  In fact, vertical      */
/* lines that attempt to use the pattern register will appear */
/* either solid or invisible depending on whether or not the  */
/* x coordinate falls on a 1 or 0 in the pattern mask.        */
/*                                                            */
/* To overcome this, we invoke this function from the low     */
/* level line drawing code if a styled line is detected.      */
/* Once here, we step along the line, pel by pel, checking    */
/* to see if we are visible and if the current pattern bit    */
/* is a '1'.  If so, we call DrawPel_8514() to light the      */
/* pel for our current position.                              */
/*                                                            */
/* We still use the PattXAddr to keep track of our current    */
/* location within the Pattern as we move from line to line   */
/* during the PolyLine() call.                                */
/**************************************************************/
VOID eddl_BresenhamOne(VOID)

{
    LONG        BresK1;            /* Bresenham values..              */
    LONG        BresK2;            /*                                 */
    LONG        BresET;            /*                                 */
    LONG        DeltaX;            /* Line dimensions..               */
    LONG        DeltaY;            /*                                 */
    LONG        DeltaSwap;         /*                                 */
    SHORT       Direction;         /* The octant number               */
    DevPoint    MajorStep;         /* Steps to use in algorithm       */
    DevPoint    BothStep;          /*                                 */
    BYTE        BothStepCode;      /* Steps to use for plot-step      */
    BYTE        MajorStepCode;     /*                                 */
    SHORT       Xpos;              /* Temporary for loop              */
    SHORT       Ypos;              /*                                 */
    SHORT       Xstart;            /* Used to reset start position    */
    SHORT       Ystart;            /* for each clip rectangle         */
    LONG        ETstart;           /*                                 */
    BOOL        StartedLine;       /*                                 */
    SHORT       LastStep;          /* Used for accumulating plot-steps*/
    BYTE        RunLength;         /*                                 */
    SHORT       RunIndex;          /*                                 */
    SHORT       TempPattern;       /* For pattern updates             */
    BOOL        XisMajor;          /*                                 */
    lpClipRectangle pClipRect;     /* For eliminating lines           */
    SHORT       ClipResult;        /*                                 */
    SHORT       StepsToDest;       /* For bresenham drawing           */
    SHORT       StepsInDest;       /*                                 */
    SHORT       PatStore;          /* To control pattern when drawing */
    SHORT       PatInc;            /* pels                            */

    LONG        i;                 /* Loop variable                   */
    SHORT       cloop;             /* Loop variable                   */

#ifdef _8514
    USHORT      usBitMask;
    USHORT      usPatternMask;
    USHORT      TotalMajorAxisLength;
#endif

    /******************************************************************/
    /* Start by trying to establish that the line is either outside   */
    /* the destination pixel map or it is outside ALL the current clip*/
    /* rectangles so we don't have to draw it.                        */
    /******************************************************************/
    if (AIxfer.usCallType == DISJOINT_CALL)
    {
        /**************************************************************/
        /* Reset the pattern position for a disjoint line because     */
        /* the 386 code calls off to this function before it gets a   */
        /* chance to reset the pattern postion                        */
        /**************************************************************/
#ifndef   _8514
        ShadowXGARegs.PatXAddr = 0;
#else
        Shadow8514Regs.PatXAddr = 0;
#endif
    }

    /******************************************************************/
    /* First try the destination pixel map..                          */
    /******************************************************************/
    SPad.ClipRect[0].X = 0;
    SPad.ClipRect[0].Y = 0;
    SPad.ClipRect[1].X = SPad.BitmapSize.X;
    SPad.ClipRect[1].Y = SPad.BitmapSize.Y;

    /******************************************************************/
    /* eddl_Intersect works on SPad.ClipRect (set up above) and       */
    /* Spad.(start/end)point which will be set up because this        */
    /* routine is called from PMLINE.                                 */
    /******************************************************************/
    if (eddl_IntersectLine() == NO_INTERSECTION)
    {
        /**************************************************************/
        /* There is no intersection with the destination bitmap so    */
        /* just update the pattern count and do whatever else is      */
        /* necessary to emulate the hardware then exit.               */
        /**************************************************************/
        UpdateShadowRegisters();
#ifndef   _8514
        TempPattern = ShadowXGARegs.PatXAddr;
        TempPattern += max(abs(SPad.endpoint.x - SPad.startpoint.x),
                           abs(SPad.endpoint.y - SPad.startpoint.y));
        ShadowXGARegs.PatXAddr = AIxfer.usPatEnd = TempPattern & (USHORT)0x0F;
        TransferShadowRegisters(TSR_COORDINATES);
#else
        TempPattern = Shadow8514Regs.PatXAddr;
        TempPattern += max(abs(SPad.endpoint.x - SPad.startpoint.x),
                           abs(SPad.endpoint.y - SPad.startpoint.y));
        Shadow8514Regs.PatXAddr = AIxfer.usPatEnd = TempPattern & (USHORT)0x0F;
#endif
        return;
    }

    /******************************************************************/
    /* Now go through each clip rectangle until we hit an intersection*/
    /* or we've done them all.                                        */
    /******************************************************************/
// Start of           
//
// Changed to following FOR LOOP to use the clipping information from the
// AIxfer structure instead of the DC.  This allows the function to work
// regardless of whether we came from Polyline or DrawLinesInPath.  This
// fixed the problem of the dashed line being drawn or not drawn at the
// correct times.  Especially when one or more         are present on the
// desktop.  @RCW
//
//        for ( i = 0, pClipRect = pdc->DCIClipRects,
//                                             ClipResult = NO_INTERSECTION;
//              (i < pdc->DCIClipNum) && (ClipResult == NO_INTERSECTION);
//              i++, pClipRect++ )

    for ( i = 0, pClipRect = AIxfer.pClipRects, ClipResult = NO_INTERSECTION;
          (i < AIxfer.cClipRects) && (ClipResult == NO_INTERSECTION);
          i++, pClipRect++ )

// End of Defect 69316
    {
        /**************************************************************/
        /* The clip rectangle we want is the intersection between the */
        /* bitmap and the clip rectangle.                             */
        /**************************************************************/
        SPad.ClipRect[0].X = max(pClipRect->X0, (USHORT)0);
        SPad.ClipRect[1].X = min(pClipRect->X1, SPad.BitmapSize.X);
        SPad.ClipRect[0].Y = max(pClipRect->Y0, (USHORT)0);
        SPad.ClipRect[1].Y = min(pClipRect->Y1, SPad.BitmapSize.Y);

        /**************************************************************/
        /* What's the answer to our clipping question?                */
        /**************************************************************/
        ClipResult = eddl_IntersectLine();
    }

    if (ClipResult == NO_INTERSECTION)
    {
        /**************************************************************/
        /* There is no need to draw the line so update the pattern    */
        /* count and return.                                          */
        /**************************************************************/
        UpdateShadowRegisters();
#ifndef _8514
        TempPattern = ShadowXGARegs.PatXAddr;
        TempPattern += max(abs(SPad.endpoint.x - SPad.startpoint.x),
                            abs(SPad.endpoint.y - SPad.startpoint.y));
        ShadowXGARegs.PatXAddr = AIxfer.usPatEnd = TempPattern & (USHORT)0x0F;
        TransferShadowRegisters(TSR_COORDINATES);
#else
        TempPattern = Shadow8514Regs.PatXAddr;
        TempPattern += max(abs(SPad.endpoint.x - SPad.startpoint.x),
                            abs(SPad.endpoint.y - SPad.startpoint.y));
        Shadow8514Regs.PatXAddr = AIxfer.usPatEnd = TempPattern & (USHORT)0x0F;
#endif
        return;
    }


    /******************************************************************/
    /* First work out which octant the line will appear in.           */
    /* (This emulates the code in the 386 as does the bresenham line  */
    /* drawing as far as possible).                                   */
    /******************************************************************/
    XisMajor = TRUE;
    Direction = 0;
    DeltaY = (LONG)SPad.endpoint.y - (LONG)SPad.startpoint.y;
    if (DeltaY < 0)
    {
        DeltaY = -DeltaY;
        Direction += YNEG;
    }

    DeltaX = (LONG)SPad.endpoint.x - (LONG)SPad.startpoint.x;
    if (DeltaX < 0)
    {
        DeltaX = -DeltaX;
        Direction += XNEG;
    }

    if (DeltaY > DeltaX)
    {
        DeltaSwap = DeltaX;
        DeltaX = DeltaY;
        DeltaY = DeltaSwap;
        Direction += YMAJOR;
        XisMajor = FALSE;
    }

    /******************************************************************/
    /* By this point DeltaX is the major dimension (ie the number of  */
    /* steps) and the octant is determined by Direction.  We will     */
    /* use a look up table to get a pair of offsets for a major only  */
    /* and a major and minor step for the correct octant.             */
    /*                                                                */
    /*                .            |            .                     */
    /*                   .      7  |  3      .                        */
    /*                      .      |      .                           */
    /*               6         .   |   .         2                    */
    /*                            .|.                                 */
    /*           ------------------*------------------                */
    /*                         .   |   .                              */
    /*               4      .      |      .      0                    */
    /*                   .      5  |  1      .                        */
    /*                .            |            .                     */
    /*                             |                                  */
    /*                                                                */
    /* When we are leading the line towards the destination bitmap we */
    /* will use MajorStep and BothSteps but once we are actually      */
    /* drawing pels we will use the plot and step capabilities of the */
    /* hardware so we have a mapping from the octant values above to  */
    /* draw and step direction octants..                              */
    /*                                                                */
    /*              MajorStep   BothStep                              */
    /*                                                                */
    /*      0 ->        0           7                                 */
    /*      1 ->        6           7                                 */
    /*      2 ->        0           1                                 */
    /*      3 ->        2           1                                 */
    /*      4 ->        4           5                                 */
    /*      5 ->        6           5                                 */
    /*      6 ->        4           3                                 */
    /*      7 ->        2           3                                 */
    /*                                                                */
    /* So pick up the steps from our look up tables..                 */
    /*                                                                */
    /* NB. Don't forget that these tables are preshifted so that they */
    /* are in the right format to be combined and sent to the hardware*/
    /*                                                                */
    /******************************************************************/
    BothStep = BresSteps[Direction].Both;
    MajorStep = BresSteps[Direction].Major;
    BothStepCode = PlotSteps[Direction].Both;
    MajorStepCode = PlotSteps[Direction].Major;

    /******************************************************************/
    /* Now work out BresK1, BresK2 and BresET..                       */
    /* DeltaY and DeltaX are such that 0 <= DeltaY <= DeltaX <= 65536 */
    /******************************************************************/
    BresK1 = 2*DeltaY;
    BresK2 = 2*(DeltaY - DeltaX);
    BresET = 2*DeltaY - DeltaX;

    /******************************************************************/
    /* We must make the lines retraceable such that the line x1,y1 to */
    /* x2,y2 is the same as the line x2,y2 to x1,y1 by adjusting the  */
    /* error term.                                                    */
    /******************************************************************/
    if ((MajorStepCode == 80) || (MajorStepCode == 144))
    {
        BresET = BresK2 + ((BresET - BresK2 - 1)%(BresK1 - BresK2));
    }

    /******************************************************************/
    /* If the Pixel Operation values indicates that we shouldn't be   */
    /* plotting the first point then advance one point along the line */
    /******************************************************************/
    /******************************************************************/
    /* pixopwork is set up by pmlines                                 */
    /******************************************************************/
    if ((SPad.pixopwork & DRAW_MODE_MASK) == DRAW_MODE_NO_FIRST_PEL)
    {
        if (BresET >= 0)
        {
            SPad.startpoint.x += BothStep.X;
            SPad.startpoint.y += BothStep.Y;
            BresET += BresK2;
        }
        else
        {
            SPad.startpoint.x += MajorStep.X;
            SPad.startpoint.y += MajorStep.Y;
            BresET += BresK1;
        }

        --DeltaX;

    }

#ifdef _8514
    /******************************************************************/
    /* Only draw the first pel during the first line of the polyline. */
    /* Calculate the number of Pels drawn, DeltaX + 1, so that our    */
    /* pattern location can be saved later and used by subsequent     */
    /* calls to this function.                                        */
    /******************************************************************/
    TotalMajorAxisLength  = DeltaX + 1;
    SPad.pixopwork       |= DRAW_MODE_NO_FIRST_PEL;
#endif

    /******************************************************************/
    /* The hardware plot and step function moves the destination/     */
    /* pattern pointers n-1 times when it draws n pels so it draws    */
    /* the pel which is currently pointed to and leaves the           */
    /* position at the last pel plotted.  The drawing mode register   */
    /* can be used to handle this and this solution has the benefit   */
    /* that the value used (omit last pel) is used every time a plot  */
    /* step is done.  The code above allows us to omit the first pel  */
    /* if this is required so we now have to plot all the points in   */
    /* the line.  But if we are using omit last pel then the last     */
    /* point won't be plotted.  To get round this we simply add 1 to  */
    /* the DeltaX so that an extra step is done on the line but is    */
    /* not drawn.  The fact that the hardware position at the end is  */
    /* not actually the end of the line doesn't matter.  Also this    */
    /* will not affect the line rendering because the bresenham values*/
    /* have already been worked out.                                  */
    /******************************************************************/
    ++DeltaX;

    /******************************************************************/
    /* Now there is a good chance that we will be starting outside the*/
    /* destination bitmap so we want to avoid calling the hardware for*/
    /* drawing until we have to.  How do we work out how many steps   */
    /* we can take before we need to start drawing the pels?  We      */
    /* aren't going to use clipping because that is what this routine */
    /* is all about avoiding (but note that in theory it should be    */
    /* possible to work out an error term and a start position just   */
    /* inside the destination bitmap without using iteration).  What  */
    /* we will do is advance N steps then see how close we are and    */
    /* repeat this until we are close enough to start drawing.  For   */
    /* want of a better term this method will be called the 'easiest  */
    /* solution' algorithm.                                           */
    /******************************************************************/
    StepsToDest = 0;

    while ((SPad.startpoint.x <= -BRES_BATCH_SIZE) ||
           (SPad.startpoint.x >= (SPad.BitmapSize.X+BRES_BATCH_SIZE)) ||
           (SPad.startpoint.y <= -BRES_BATCH_SIZE) ||
           (SPad.startpoint.y >= (SPad.BitmapSize.Y+BRES_BATCH_SIZE)))
    {
        /**************************************************************/
        /* SPad.startpoint is still not close enough so take          */
        /* BRES_BATCH_SIZE steps..                                    */
        /**************************************************************/
        for ( i=0; i<BRES_BATCH_SIZE; i++ )
        {
            if ( BresET >= 0)
            {
                SPad.startpoint.x += BothStep.X;
                SPad.startpoint.y += BothStep.Y;
                BresET += BresK2;
            }
            else
            {
                SPad.startpoint.x += MajorStep.X;
                SPad.startpoint.y += MajorStep.Y;
                BresET += BresK1;
            }
        }
        StepsToDest += BRES_BATCH_SIZE;
    }

    /******************************************************************/
    /* And adjust the length to the number of steps left to do.       */
    /******************************************************************/
    DeltaX -= StepsToDest;

    /******************************************************************/
    /* Now update the pattern count to allow for the steps we have    */
    /* taken.                                                         */
    /******************************************************************/
    UpdateShadowRegisters();
    #ifndef   _8514
    TempPattern = ShadowXGARegs.PatXAddr;
    #else
    TempPattern = Shadow8514Regs.PatXAddr;
    #endif
    TempPattern += StepsToDest;
    TempPattern = TempPattern & (USHORT)0x0F;

#ifdef _8514
    usPatternMask = LinePatternsBitmap[ AIxfer.usPatType ];
#endif

    /******************************************************************/
    /* Keep copy of start point so beginning of each line can be reset*/
    /* for each clip rectangle                                        */
    /******************************************************************/
    Xstart = SPad.startpoint.x;
    Ystart = SPad.startpoint.y;
    ETstart = BresET;

    for ( cloop = 0, pClipRect = AIxfer.pClipRects;
          cloop < AIxfer.cClipRects;
          cloop++, pClipRect++     )
    {
        SPad.ClipRect[0].X =
                           pClipRect->X0;
        SPad.ClipRect[1].X =
                           pClipRect->X1;
        SPad.ClipRect[0].Y =
                           pClipRect->Y0;
        SPad.ClipRect[1].Y =
                           pClipRect->Y1;

        /******************************************************************/
        /* Now we are close enough to start actually batching the pels up */
        /* for PMPLOTSTEP.  After every call to PMPLOTSTEP we will check  */
        /* to see if we're now outside the destination bitmap.  Note that */
        /* with a 16 byte buffer and each byte potentially equalling 16   */
        /* pels this means we could overdraw by up to 256 pels, and that  */
        /* this also means there is no danger of getting anywhere near the*/
        /* guard area although we could obviously waste some time..       */
        /******************************************************************/

        /******************************************************************/
        /* Plotting.                                                      */
        /* Points to be plotted are accumulated into plot-step runs and   */
        /* these runs are accumulated into RUNS_BATCH_SIZE Dwords of      */
        /* plot-step data and when this buffer is full we call            */
        /* eddh_PMPLOTSTEP.                                               */
        /******************************************************************/

        /******************************************************************/
        /* Take a copy of SPad.startpoint.x and SPad.startpoint.y to work */
        /* on in the loop as the AIxfer coordinates will be out of step   */
        /* with the loop coordinates because of the batching used.        */
        /******************************************************************/
        Xpos = Xstart;
        Ypos = Ystart;
        BresET = ETstart;
        StartedLine = FALSE;

        /******************************************************************/
        /* Tell eddh_PMPLOTSTEP where to look for the plot step codes.    */
        /* Clear the runstore.                                            */
        /******************************************************************/
        AIxfer.pPlotStepCodes = SPad.RunStore;
        for (i=0; i<RUN_BATCH_SIZE; i++ ) SPad.RunStore[i] = 0;

        /******************************************************************/
        /* Set up starting values for plot step accumulation.             */
        /******************************************************************/
        LastStep = NEITHER_STEP;
        RunLength = 0;
        RunIndex = 0;

        for ( i=0; i < DeltaX; ++i )
        {
            /**************************************************************/
            /* Do bresenhams algorithm and accumulate plot-steps as well. */
            /**************************************************************/
            if (BresET >= 0)
            {
                if (  (Xpos >= SPad.ClipRect[0].X)
                   && (Xpos <= SPad.ClipRect[1].X)
                   && (Ypos >= SPad.ClipRect[0].Y)
                   && (Ypos <= SPad.ClipRect[1].Y) )
                {
                    if (StartedLine == FALSE)
                    {
                        StartedLine = TRUE;
                        SPad.startpoint.x = Xpos;
                        SPad.startpoint.y = Ypos;
                        if (XisMajor)
                            PatStore = TempPattern + abs(Xstart - Xpos);
                        else
                            PatStore = TempPattern + abs(Ystart - Ypos);
                        PatStore &= 0x0F;
                        PatInc = 0;
#ifdef _8514
                        /******************************************************/
                        /* Since this is the first run, initialize our        */
                        /* position within the pattern.                       */
                        /******************************************************/
                        usBitMask = 0x8000 >> PatStore;
#endif
                    }
                    /**********************************************************/
                    /* We are within the clip bounds so collect up the step   */
                    /* into our batch.                                        */
                    /**********************************************************/
                    if ((LastStep == BOTH_STEP) || (LastStep == NEITHER_STEP))
                    {
                        /******************************************************/
                        /* Because LastStep might have been NEITHER_STEP      */
                        /******************************************************/
                        LastStep = BOTH_STEP;

#ifndef _8514
                        /******************************************************/
                        /* Same direction as last time so try and add it to   */
                        /* the current run.                                   */
                        /******************************************************/
                        if (RunLength < MAX_RUN_LENGTH)
                        {
                            /**************************************************/
                            /* We can add this pel to the current run..       */
                            /**************************************************/
                            RunLength++;
                        }
                        else
                        {
                            /**************************************************/
                            /* We need a new run.  Store the last one first   */
                            /**************************************************/
                            SPad.RunStore[RunIndex] =
                                                    BothStepCode | (RunLength);
                            RunIndex++;

                            /**************************************************/
                            /* And start a new run.  LastStep is still the    */
                            /* same - only need to alter RunLength.           */
                            /**************************************************/
                            RunLength = 1;
                        }
#endif
                    }
                    else
                    {
#ifndef _8514
                        /******************************************************/
                        /* The last step was not in the same direction as     */
                        /* this one so we need a new run.  Store the old one  */
                        /* first.                                             */
                        /******************************************************/
                        SPad.RunStore[RunIndex] =
                                                   MajorStepCode | (RunLength);
                        RunIndex++;
#endif
                        /******************************************************/
                        /* And start a new one - here we need to set LastStep */
                        /* as well.                                           */
                        /******************************************************/
                        LastStep = BOTH_STEP;
                        RunLength = 1;
                    }
#ifdef _8514
                    /******************************************************/
                    /* Plot a pel only if we're not clipped out.          */
                    /******************************************************/
                    if (usPatternMask & usBitMask)
                    {
                        DrawPel_8514( Xpos, Ypos );
                    }
#endif
                }
                /******************************************************/
                /* Now do the bresenham step.                         */
                /******************************************************/
                Xpos += BothStep.X;
                Ypos += BothStep.Y;
                BresET += BresK2;
            }

            else

            {

                if (  (Xpos >= SPad.ClipRect[0].X)
                   && (Xpos <= SPad.ClipRect[1].X)
                   && (Ypos >= SPad.ClipRect[0].Y)
                   && (Ypos <= SPad.ClipRect[1].Y) )
                {
                    if (StartedLine == FALSE)
                    {
                        StartedLine = TRUE;
                        SPad.startpoint.x = Xpos;
                        SPad.startpoint.y = Ypos;
                        if (XisMajor)
                            PatStore = TempPattern + abs(Xstart - Xpos);
                        else
                            PatStore = TempPattern + abs(Ystart - Ypos);
                        PatStore &= 0x0F;
                        PatInc = 0;
#ifdef _8514
                        /******************************************************/
                        /* Since this is the first run, initialize our        */
                        /* position within the pattern.                       */
                        /******************************************************/
                        usBitMask = 0x8000 >> PatStore;
#endif
                    }
                    /**********************************************************/
                    /* We are within the clip bounds so collect up the step   */
                    /* into our batch.                                        */
                    /**********************************************************/
                    if ((LastStep == MAJOR_STEP) || (LastStep == NEITHER_STEP))
                    {
                        /******************************************************/
                        /* Because LastStep might have been NEITHER_STEP      */
                        /******************************************************/
                        LastStep = MAJOR_STEP;
#ifndef _8514
                        /******************************************************/
                        /* Same direction as last time so try and add it to   */
                        /* the current run.                                   */
                        /******************************************************/
                        if (RunLength < MAX_RUN_LENGTH)
                        {
                            /**************************************************/
                            /* We can add this pel to the current run..       */
                            /**************************************************/
                            RunLength++;
                        }
                        else
                        {
                            /**************************************************/
                            /* We need a new run.  Store the last one first.  */
                            /**************************************************/
                            SPad.RunStore[RunIndex] =
                                                   MajorStepCode | (RunLength);
                            RunIndex++;

                            /**************************************************/
                            /* And start a new run.  LastStep is still the    */
                            /* same - only need to alter RunLength.           */
                            /**************************************************/
                            RunLength = 1;
                        }
#endif
                    }
                    else
                    {
#ifndef _8514
                        /******************************************************/
                        /* The last step was not in the same direction as     */
                        /* this one so we need a new run.  Store the old one  */
                        /* first.                                             */
                        /******************************************************/
                        SPad.RunStore[RunIndex] = BothStepCode | (RunLength);
                        RunIndex++;
#endif
                        /******************************************************/
                        /* And start a new one - here we need to set LastStep */
                        /* as well.                                           */
                        /******************************************************/
                        LastStep = MAJOR_STEP;
                        RunLength = 1;
                    }
#ifdef _8514
                    /******************************************************/
                    /* Plot a pel only if we're not clipped out.          */
                    /******************************************************/
                    if (usPatternMask & usBitMask)
                    {
                        DrawPel_8514( Xpos, Ypos );
                    }
#endif
                }
                /******************************************************/
                /* Now do the bresenham step.                         */
                /******************************************************/
                Xpos += MajorStep.X;
                Ypos += MajorStep.Y;
                BresET += BresK1;
            }
            /**************************************************************/
            /* We've added a pel to the plot step so increase the PatInc  */
            /**************************************************************/
            PatInc++;

#ifdef _8514

            /**************************************************************/
            /* For each step in the line shift the bit mask right (Make   */
            /* sure we don't shift past the right end).                   */
            /**************************************************************/
            if (usBitMask == 1)
                usBitMask = 0x8000;
            else
                usBitMask >>= 1;

#endif

            /**************************************************************/
            /* Check whether we need to output the pels now.              */
            /**************************************************************/
            if (RunIndex == RUN_BATCH_SIZE)
            {
                /**********************************************************/
                /* Set the pattern start position before drawing.         */
                /**********************************************************/
#ifndef   _8514
                ShadowXGARegs.PatXAddr = PatStore;
                TransferShadowRegisters(TSR_COORDINATES);
                (*(*pDrawFunctions)[index_PMPLOTSTEP])();
                RunIndex = 0;
#endif

                /**********************************************************/
                /* Now update the pattern position and get ready for next */
                /* run.                                                   */
                /**********************************************************/
                PatStore += PatInc;
                PatStore &= 0x0F;
                PatInc = 0;

                /**********************************************************/
                /* Check against the bounds of the bitmap..               */
                /**********************************************************/
                if ((Xpos < -BRES_BATCH_SIZE) ||
                    (Ypos < -BRES_BATCH_SIZE) ||
                    (Xpos > (SPad.BitmapSize.X+BRES_BATCH_SIZE)) ||
                    (Ypos > (SPad.BitmapSize.Y+BRES_BATCH_SIZE)))
                {
                    /******************************************************/
                    /* We've drawn enough pels now so quit the loop       */
                    /* (setting LastStep as a flag to show why we quit)   */
                    /******************************************************/
                    LastStep = NEITHER_STEP;
                    break;
                }
            }
        }

        StepsInDest = (short)i;

#ifndef   _8514
        if (LastStep != NEITHER_STEP)
        {
            /**************************************************************/
            /* We exited the loop because we got to the end of the line   */
            /* so stuff the pels which were being accumulated into the    */
            /* run batch (there will _always_ be room for another entry   */
            /* here becasue of the test which has been done above)        */
            /**************************************************************/
            if (LastStep == MAJOR_STEP)
            {
                SPad.RunStore[RunIndex] = MajorStepCode | (RunLength);
            }
            else
            {
                SPad.RunStore[RunIndex] = BothStepCode | (RunLength);
            }
            RunIndex++;

            ShadowXGARegs.PatXAddr = PatStore;

            TransferShadowRegisters(TSR_COORDINATES);
            (*(*pDrawFunctions)[index_PMPLOTSTEP])();

            /**************************************************************/
            /* Now, if you remember when we fiddled with DeltaX so that   */
            /* the whole line would be drawn when we were using last pel  */
            /* null mode that added one to the line's length.  As we've   */
            /* got to this point we must have drawn to the end of the line*/
            /* but because of that fiddle the pattern position will be    */
            /* one too far.  So decrease it by one..                      */
            /**************************************************************/
            PatStore = ShadowXGARegs.PatXAddr;
            PatStore--;
            ShadowXGARegs.PatXAddr = PatStore & (USHORT)0x0F;
        }
#endif

    }

    /******************************************************************/
    /* Now update the pattern count in case we gave up because a line */
    /* exited the destination bitmap.                                 */
    /* Again, we can cast DeltaX to an USHORT because it WILL         */
    /* be positive by here.                                           */
    /******************************************************************/
#ifndef   _8514
    TempPattern = ShadowXGARegs.PatXAddr;
    TempPattern += ((USHORT)DeltaX - StepsInDest);
    ShadowXGARegs.PatXAddr = AIxfer.usPatEnd = TempPattern & (USHORT)0x0F;
    TransferShadowRegisters(TSR_COORDINATES);
#else
    TempPattern = Shadow8514Regs.PatXAddr;
    TempPattern += (USHORT)TotalMajorAxisLength;
    Shadow8514Regs.PatXAddr = AIxfer.usPatEnd = TempPattern & (USHORT)0x0F;
#endif
    return;

}

/**********************************************************************/
/* This routine is for use ONLY within eddlpoly as it has parameters  */
/* passed by mutual understanding within this code file!!!            */
/* It determines whether there is an intersection between the line    */
/* (SPad.startpoint.x, SPad.startpoint.y) ->                          */
/*                            (Spad.endpoint.x, SPad.endpoint.y)      */
/* and the rectangle SPad.ClipRect.  To do this it uses a midpoint    */
/* sub-division scheme.  The line is tested and if a definite         */
/* intersection occurs then this is returned.  Note that as well as   */
/* one point in SPad.ClipRect a definite intersection can also be     */
/* recognised when the line goes from ONLY above (ie not above and    */
/* left or above and right) to ONLY below SPad.ClipRect or from ONLY  */
/* left to ONLY right.  If no intersection occurs then this is also   */
/* returned.  Next, the line is divided in two and both these lines   */
/* are checked.  If a definite intersection is found then this can    */
/* be returned otherwise one of the two lines can be discarded as it  */
/* will have a definite non-intersection.  The dividing process then  */
/* repeats.  This function returns from all over the place - not      */
/* good practice but probably not important.                          */
/**********************************************************************/
USHORT eddl_IntersectLine(VOID)
{
    ULONG    StartCode;
    ULONG    EndCode;
    DevPoint Start;
    DevPoint End;
    DevPoint Mid;

    /******************************************************************/
    /* Take a local copy of the endpoints.                            */
    /******************************************************************/
    Start.X = SPad.startpoint.x;
    Start.Y = SPad.startpoint.y;
    End.X = SPad.endpoint.x;
    End.Y = SPad.endpoint.y;

    /******************************************************************/
    /* Work out the outcodes                                          */
    /******************************************************************/
    StartCode = eddl_Outcode(Start);
    EndCode   = eddl_Outcode(End);

    /******************************************************************/
    /* None of these has worked so now start to sub-divide the line   */
    /******************************************************************/
    for (;;) /* ever and ever (until a return from the loop) */
    {
        /**************************************************************/
        /* Try to accept/reject the line here                         */
        /**************************************************************/
        if ((StartCode & EndCode) != 0)
            break;

        if (StartCode == 0 || EndCode == 0)
            return INTERSECTION;

        /**************************************************************/
        /* Try a test for a definite intersection but neither point   */
        /* in rectangle.                                              */
        /**************************************************************/
        if (((StartCode | EndCode) == (CS_ABOVE | CS_BELOW)) ||
            ((StartCode | EndCode) == (CS_LEFT | CS_RIGHT)))
            return INTERSECTION;

        /**************************************************************/
        /* Sub-divide the line                                        */
        /* edb fixed 73758: change midpoint calculation to bias       */
        /* towards Start                                              */
        /**************************************************************/
        #define midpoint(x1,x2) (x1+((x2-x1)/(USHORT)2))
        // midpoint(x1,x2) (x1+((x2-x1-(USHORT)1)/(USHORT)2)+(USHORT)1)
        Mid.X = midpoint(Start.X, End.X);
        Mid.Y = midpoint(Start.Y, End.Y);

        /**************************************************************/
        /* Get the code for the first 1/2 line                        */
        /**************************************************************/
        StartCode = eddl_Outcode(Start);
        EndCode   = eddl_Outcode(Mid);

        /**************************************************************/
        /* If we can't reject the line outright then can forget the   */
        /* other half because we will be able to reject it outright   */
        /**************************************************************/
        if ((StartCode & EndCode) == 0)
        {
            /**********************************************************/
            /* We can't reject this half outright so we will use it   */
            /* and forget the other half.                             */
            /**********************************************************/
            End = Mid;
        }
        else
        {
            /**************************************************************/
            /* edb fixed 73758: we can get here because Start == Mid and  */
            /* the Outcode is nonzero.  So reject here if Start == Mid    */
            /**************************************************************/
            if ((Start.X == Mid.X) && (Start.Y == Mid.Y))
                break;

            /**********************************************************/
            /* We rejected the first half and so will use the second  */
            /* half.  Get the outcodes for it here.                   */
            /**********************************************************/
            Start = Mid;
            StartCode = EndCode;
            EndCode = eddl_Outcode(End);
        }
    }

    return NO_INTERSECTION;

} /* eddl_IntersectLine */

/**********************************************************************/
/* This routine is for use ONLY within eddlpoly as it has parameters  */
/* passed by mutual understanding within this code file!!!            */
/* It returns the outcodes for a point passed in and the rectangle    */
/* in SPad.ClipRect.                                                   */
/**********************************************************************/
ULONG eddl_Outcode(DevPoint Point)
{
    ULONG   Outcode;

    /******************************************************************/
    /* Right, do the C-S stuff.                                       */
    /* Not a lot of comments here but then who needs them?            */
    /******************************************************************/
    if (Point.X < SPad.ClipRect[0].X)
    {
        Outcode = CS_LEFT;
    }
    else if (Point.X > SPad.ClipRect[1].X)
    {
        Outcode = CS_RIGHT;
    }
    else
    {
        Outcode = 0;
    }

    if (Point.Y < SPad.ClipRect[0].Y)
    {
        return(Outcode | CS_ABOVE);
    }
    else if (Point.Y > SPad.ClipRect[1].Y)
    {
        return(Outcode | CS_BELOW);
    }
    else
    {
        return (Outcode);
    }
}
