/*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          = EDDBMARK                                       */
/*                                                                    */
/*   Description     = Display Device Driver Minor Function :         */
/*                     PolyMarker                                     */
/*                                                                    */
/*   Function        = Draws a series of one or more markers at the   */
/*                     current position and then each of the          */
/*                     specified positions                            */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_GRE_XFORMS
#define INCL_DDIMISC
#define INCL_GRE_MARKERS
#include <eddinclt.h>

#include <eddacone.h>
#include <eddbcone.h>
#include <eddecone.h>
#include <eddhcone.h>

#include <edddtypt.h>
#include <eddhtype.h>

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

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

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

extern PPFNL               EnginesDispatchTable;
extern DDTType             DDT;
extern BYTE                WinToXway[];
extern BITBLTPB            AIxfer;
#ifndef   _8514
extern MMReg               ShadowXGARegs;
extern pMMReg              pRealXGARegs;
extern pMMReg              pXGARegs;
#else
#include                   <8514.h>
extern MM8514Reg           Shadow8514Regs;
extern pMM8514Reg          p8514Regs;
#endif
extern BltSPad             SPad;
extern ULONG               PixelOp;

extern ULONG               MarkerPhys;
extern ULONG               MarkerSys ;
extern POINTL              MarkerCoords[];
extern BitmapHeader        MarkerBitmapHeader;

extern CURSORDATA           cursor_data;

extern SHORT                softDrawInUse;

#ifdef SDBM20
extern ULONG                    LinePatternCur ;
extern ULONG                    LinePatternPhys ;
extern ULONG                    LinePatternSys ;
extern ULONG                    MarkerCur ;
extern ULONG                    pCurCacheBasePhy ;
extern ULONG                    pSysCacheStartPhy;
extern ULONG                    pPhunkPhys;
extern drawFunctionsTable       softDrawTable ;
extern drawFunctionsTable       hardDrawTable ;
extern SHORT                    foregroundSession ;
#endif /* SDBM20 */

extern pDrawFunctionsTable      pDrawFunctions ;

/**********************************************************************/
/* private functions                                                  */
/**********************************************************************/
VOID DRIVERCALL OutputMarker( VOID );


/**********************************************************************/
/*                                                                    */
/*   PolyMarker draws a sequence of one or more markers using the     */
/* current marker set and symbol                                      */
/*                                                                    */
/*   The first marker is drawn at the current position; subsequent    */
/* markers are drawn at co-ords in a given array.  The co-ords are    */
/* given in world or screen co-ords.  The current position is updated */
/* to the last co-ord.                                                */
/*                                                                    */
/*   The marker is drawn using the foreground and background colour   */
/* and mixes given in the marker bundle attributes.  The marker is    */
/* centered on the given co-ord.                                      */
/*                                                                    */
/*   The bitmap which defines the current marker and the width and    */
/* height of this bitmap are held in the DC instance data.  A         */
/* simulation required flag is also held in the instance data.  These */
/* are set when the current marker bundle attributes are set.         */
/*                                                                    */
/*   If simulation is required but the device driver cannot call the  */
/* Engine then an alternative marker symbol, taken from the instance  */
/* data, is used.                                                     */
/*                                                                    */
/**********************************************************************/

DDIENTRY eddb_PolyMarker (HDC        hdc,
                          PPOINTL    Points,
                          ULONG      NoOfPoints,
                          PDC        pdcArg,
                          ULONG      FunN)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG              MarkersToOutput; /* # to output in one pass    */
    USHORT             PointsToOutput;  /* loop control variable      */
    ULONG              MarkersLeft;     /* Number of markers left to  */
                                        /* output                     */
    USHORT             StartIndex;      /* Start of batch in buffer   */
    ULONG              Result;          /* Return value               */
    RECTS              MarkerOffset;    /* adjustment from marker     */
                                        /* centre to marker box       */
    RECTS              Bounds;          /* bounds for this operation  */
    USHORT             CharWidth;       /* prop-spaced char x dimnsion*/

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

    /******************************************************************/
    /* If the number of markers to draw is zero then there is nothing */
    /* to do                                                          */
    /******************************************************************/
    if ( !NoOfPoints )
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD);
        return(OK);
    }

    /******************************************************************/
    /* If the function is being called within an area or path         */
    /* definition then we log an error and exit                       */
    /******************************************************************/
    if ( FunNTest(COM_AREA | COM_PATH) )
    {
        if (FunNTest(COM_AREA))
        {
            LogError(PMERR_INV_IN_AREA);
        }
        else /* COM_PATH */
        {
            LogError(PMERR_INV_IN_PATH);
        }

        goto POLYMARKER_ERR_EXIT;

    } /* within path or area definition */

    /******************************************************************/
    /* Set up default return code                                     */
    /******************************************************************/
    Result = OK;

    /******************************************************************/
    /* If simulation is required and the COM_DEVICE is not set        */
    /* then the call can be returned to the Engine; otherwise use     */
    /* the nearest marker type (as set up when marker attributes set) */
    /* Simulations are needed when the marker set is a font with one  */
    /* or more of ITALIC, BOLD, UNDERSCORE or STRIKEOUT enabled or is */
    /* an outline font                                                */
    /******************************************************************/
    if ( pdc->DCIMarkerSimReq )
    {
        if (FunNTest(COM_DEVICE))
        {
            /**********************************************************/
            /* can't pass this on to the default handler so log a     */
            /* warning and carry on (produce an unattributed marker)  */
            /**********************************************************/
            LogWarning(PMERR_UNSUPPORTED_ATTR);
        }
        else /* OK to call the default handler */
        {
            ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_IGNORE_TIME);
            return (EnginesDispatchTable[NGrePolyMarker & 0xff](
                                                            hdc,
                                                            Points,
                                                            NoOfPoints,
                                                            pdcArg,
                                                            FunN));
        }
    }


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


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

    /******************************************************************/
    /* Return an error if there is no currently selected bitmap and   */
    /* we're expected to do some drawing                              */
    /******************************************************************/
    if ( (pdc->DCIBitmapType & BITMAP_NOT_SELECTED) &&
         FunNTest(COM_DRAW) )
    {
        LogError(PMERR_NO_BITMAP_SELECTED);
        goto POLYMARKER_ERR_EXIT;
    }


    /******************************************************************/
    /* if the marker symbol or set has changed then we need to get    */
    /* the new data                                                   */
    /******************************************************************/
    if ( pdc->DCIChanged & NEW_MARKER_SYMBOL )
    {
        if ( !edda_MarkerSetUp() )
        {
            goto POLYMARKER_ERR_EXIT;
        }
    }

    /******************************************************************/
    /* DCIMarker will contain the symbol number if one of the default */
    /* set or a pointer to a bitmap header if non-default             */
    /* This field is zero based although markers are 1 based          */
    /******************************************************************/
    if ((ULONG)pdc->DCIMarker > MARKSYM_SMALLCIRCLE)
    {
        /**************************************************************/
        /* the source bitmap is the bitmap header pointed to by       */
        /* DCIMarker                                                  */
        /**************************************************************/
        AIxfer.pbmhSrc = pdc->DCIMarker;
    }

    else /* default set */
    {
        /**************************************************************/
        /* the source bitmap is the marker bitmap header held in the  */
        /* static data segment. Put the physical address of the       */
        /* marker definition to use into the global marker bitmap     */
        /* header                                                     */
        /**************************************************************/
        AIxfer.pbmhSrc = &MarkerBitmapHeader;

        MarkerBitmapHeader.Bitmap = (lpBitmap)(MarkerSys +
                        DEF_MARKER_LENGTH * (USHORT)(pdc->DCIMarker));
        MarkerBitmapHeader.BMPhys = MarkerPhys +
                        DEF_MARKER_LENGTH * (USHORT)(pdc->DCIMarker);
    }


    /******************************************************************/
    /* copy the pointer to the destination bitmap header into the     */
    /* parameter block, which will be passed to the blt hardware      */
    /* interface function to output each marker                       */
    /******************************************************************/
    AIxfer.pbmhDest = pdc->DCISelListEntry;

    /******************************************************************/
    /* copy the pointer to clip rectangles defining the current       */
    /* region and the number of rectangles, into the parameter block  */
    /******************************************************************/
    AIxfer.pNextDestClipRect = pdc->DCIClipRects;
    AIxfer.cDestClipRects = pdc->DCIClipNum;

    /******************************************************************/
    /* initialise the pixel operation to be used if we are going to   */
    /* do some drawing.                                               */
    /* -  background source: background colour                        */
    /* -  foreground source: foreground colour                        */
    /* -  step: PxBlt                                                 */
    /* -  source pixel map: don't care                                */
    /* -  destination pixel map: Map A                                */
    /* -  pattern pixel map: Map C (screen format target)             */
    /*                       Map B ( 1,1 target)                      */
    /* -  mask pixel map: disabled                                    */
    /* -  drawing mode: don't care                                    */
    /* -  direction octant: left to right, top to bottom              */
    /******************************************************************/
    if ( FunNTest(COM_DRAW))
    {
        if (pdc->DCISelListEntry->Info.BitCount == 1)
        {
            PixelOp = BACK_SRC_BACK_COL |
                      FORE_SRC_FORE_COL |
                      STEP_PXBLT |
                      SRC_PIX_MAP_DONTCARE |
                      DST_PIX_MAP_A |
                      PAT_PIX_MAP_B |
                      MASK_PIX_MAP_OFF |
                      DRAW_MODE_DONTCARE |
                      DIR_OCTANT_LRTB;
        }
        else
        {
            PixelOp = BACK_SRC_BACK_COL |
                      FORE_SRC_FORE_COL |
                      STEP_PXBLT |
                      SRC_PIX_MAP_DONTCARE |
                      DST_PIX_MAP_A |
                      PAT_PIX_MAP_C |
                      MASK_PIX_MAP_OFF |
                      DRAW_MODE_DONTCARE |
                      DIR_OCTANT_LRTB;
        }
    }

    /******************************************************************/
    /* The passed marker positions specify the centre of the marker   */
    /* To do the blt we need the bottom left and top right so         */
    /* calculate the adjustments that need to be made to give this    */
    /* The adjustment may not be the same in both directions - if the */
    /* width or height is an even number                              */
    /* Where the marker set is a font the offsets are calculated on   */
    /* the basis of the cell width less the left and right prop-      */
    /* spaced margins.                                                */
    /*                                                                */
    /* The margin values are held in the MARKER_INFO structure        */
    /* pointed to from the bitmap header.  Note that if the marker is */
    /* not from a font then the margin values will be zero. (ie. we   */
    /* will use all of the bitmap).                                   */
    /*                                                                */
    /******************************************************************/
    if ( !(pdc->DCIChanged & MARKER_BITMAP_CREATED) )
    {
        MarkerOffset.pts1.x =
        MarkerOffset.pts2.x = AIxfer.pbmhSrc->Info.Width / (USHORT)2;
    }

    else /* non default set */
    {
        CharWidth = AIxfer.pbmhSrc->Info.Width -
                              AIxfer.pbmhSrc->MarkerInfo.MarginWidth -
                              AIxfer.pbmhSrc->MarkerInfo.MarginHeight;
        MarkerOffset.pts1.x = (CharWidth - (USHORT)1) / (USHORT)2;
        MarkerOffset.pts2.x = CharWidth / (USHORT)2;
    }

    MarkerOffset.pts1.y = AIxfer.pbmhSrc->Info.HWHeight / (USHORT)2;
    MarkerOffset.pts2.y = AIxfer.pbmhSrc->Info.Height / (USHORT)2;

    /******************************************************************/
    /* the first marker is output at the current position.            */
    /******************************************************************/
    /* copy the current h/w coordinates into the marker coordinate    */
    /* buffer first position and initialise the bounds data           */
    /******************************************************************/
    MarkerCoords[0].x = (LONG)pdc->DCICurrPosAI.X;
    Bounds.pts1.x =
    Bounds.pts2.x = (SHORT)MarkerCoords[0].x;

    MarkerCoords[0].y = (LONG)pdc->DCICurrPosAI.Y;
    Bounds.pts1.y =
    Bounds.pts2.y = (SHORT)MarkerCoords[0].y;


    /******************************************************************/
    /* the marker coordinates may need to be transformed. There is a  */
    /* buffer in the ds into which we put the h/w coordinates of the  */
    /* markers. This is MAX_MARKERS long so we can only output this   */
    /* many markers at a time. We need to output the markers in       */
    /* batches of MAX_MARKERS markers.                                */
    /* The first position for markers is the current h/w position.    */
    /* This needs to be drawn in the first batch, but omitted from    */
    /* all other batches (otherwise it would be drawn more than once) */
    /* The variable 'StartIndex' is used to indicate where the array  */
    /* of translated coordinates is currently starting from. When     */
    /* this value is zero the first point is transfered as it will    */
    /* have been the first call.                                      */
    /******************************************************************/
    MarkersLeft = NoOfPoints;
    StartIndex = 0;

    while (MarkersLeft)
    {
        /**************************************************************/
        /* The first time round this loop we are going to output the  */
        /* first marker in the current position. We need to decrement */
        /* the number of markers left to allow for this.              */
        /* This is done within the loop so that if just one marker is */
        /* asked for this loop is still entered and the single marker */
        /* is output.                                                 */
        /**************************************************************/
        if (StartIndex == 0)
        {
            MarkersLeft--;
        }

        /**************************************************************/
        /* Work out the number of markers to be output on this pass   */
        /**************************************************************/
        MarkersToOutput = min(MarkersLeft, MAX_MARKERS - 1);

        /**************************************************************/
        /* if our marker positions are in world coordinates then      */
        /* convert to h/w coordinates                                 */
        /**************************************************************/
        if (FunNTest(COM_TRANSFORM))
        {
            if ( pdc->DCIXFrmSimple )
            {
                /******************************************************/
                /* for a 1 to 1 transform world = device so just      */
                /* convert to h/w coordinates by adjusting for the dc */
                /* origin and moving the origin from bottom left to   */
                /* top left                                           */
                /******************************************************/
                for ( PointsToOutput = 0;
                      PointsToOutput < MarkersToOutput;
                      PointsToOutput++
                    )
                {
                    MarkerCoords[PointsToOutput + 1].x =
                            Points[StartIndex + PointsToOutput].x +
                                pdc->DCIOrigin.X;
                    MarkerCoords[PointsToOutput + 1].y =
                            pdc->DCIConvFactor -
                                Points[StartIndex + PointsToOutput].y;
                }
            }

            else /* not a 1 to 1 transform */
            /**************************************************************/
            /* the transform between world and device is not 1 to 1 so    */
            /* get the engine to do it                                    */
            /**************************************************************/
            {
                /******************************************************/
                /* the engine conversion takes only one buffer for    */
                /* the coordinates, ie the target coordinates are     */
                /* returned in the source buffer.  Since our source   */
                /* buffer is supplied by the app.  we don't want to   */
                /* change it, so take a copy before calling convert.  */
                /* MarkerCoords[0] contains the current position and  */
                /* is only used when StartIndex is zero.              */
                /******************************************************/
                memcpy((PVOID)&MarkerCoords[1], (PVOID)&Points[StartIndex],
                                               (8 * MarkersToOutput ));

                if ( !EnginesDispatchTable[NGreConvert & 0xff](
                                              hdc,
                                              CVTC_WORLD,
                                              CVTC_DEVICE,
                                              (PVOID)&MarkerCoords[1],
                                              MarkersToOutput,
                                              0,
                                              NGreConvert) )
                {
                    goto POLYMARKER_ERR_EXIT;
                }

                /**********************************************************/
                /* we now have device coordinates in MarkerCoords so      */
                /* convert to h/w coordinates. This is the same as for    */
                /* the 1 to 1 transform above but we take the device      */
                /* coordinates from the MarkerCoords buffer rather than   */
                /* user Points buffer                                     */
                /**********************************************************/
                for ( PointsToOutput = 0;
                      PointsToOutput < MarkersToOutput;
                      PointsToOutput++
                    )
                {
                    MarkerCoords[PointsToOutput + 1].x += pdc->DCIOrigin.X;
                    MarkerCoords[PointsToOutput + 1].y = pdc->DCIConvFactor -
                                             MarkerCoords[PointsToOutput + 1].y;
                }

            } /* not  a 1 to 1 world to device transform */

        } /* convert world to h/w coordinates */

        else /* screen coordinates */
        {
            /**************************************************************/
            /* x can be taken directly from the supplied coordinates      */
            /* but y must be adjusted for the h/w origin being top        */
            /**************************************************************/
            for ( PointsToOutput = 0;
                  PointsToOutput < MarkersToOutput;
                  PointsToOutput++
                )
            {
                MarkerCoords[PointsToOutput + 1].x =
                        Points[StartIndex + PointsToOutput].x;
                MarkerCoords[PointsToOutput + 1].y =
                        DDT.ScreenHeight - 1 -
                            Points[StartIndex + PointsToOutput].y;
            }

        } /* screen coordinates */


        /******************************************************************/
        /* If bounds are to be calculated then use the marker coordinates */
        /* to get the bounding rectangle of all the marker centre points  */
        /* (for this pass). Adjust this to the actual bounding rectangle  */
        /* by adjusting for the marker width and height (MarkerOffset)    */
        /******************************************************************/
        if ( FunNTest(COM_BOUND | COM_ALT_BOUND) ||
#ifdef DCAF                                                               //DCAF
             DCAFBoundsRequired(FunN) ||                                  //DCAF
#endif                                                                    //DCAF
             (cursor_data.cursor_status & CURSOR_SOFTWARE ) )
        {
            /**************************************************************/
            /* Update the bounds for each point after the first           */
            /* The bounds are calculated as top left, bottom right. This  */
            /* is the format required for passing h/w coordinates to      */
            /* AddBounds                                                  */
            /**************************************************************/
            for ( PointsToOutput = (USHORT)1;
                  PointsToOutput <= MarkersToOutput;
                  PointsToOutput++)
            {
                /******************************************************/
                /* there is an unnecessary assignment to              */
                /* Bounds.pts1.x here if the equality holds but this  */
                /* saves testing against Bounds.pts2.x unnecessarily  */
                /******************************************************/
                if ( Bounds.pts1.x >=
                        (SHORT)MarkerCoords[PointsToOutput].x )
                {
                    Bounds.pts1.x = (SHORT)MarkerCoords[PointsToOutput].x;
                }
                else
                {
                    if ( Bounds.pts2.x <
                                     (SHORT)MarkerCoords[PointsToOutput].x )
                    {
                        Bounds.pts2.x = (SHORT)MarkerCoords[PointsToOutput].x;
                    }
                }
                if ( Bounds.pts1.y >= (SHORT)MarkerCoords[PointsToOutput].y )
                {
                    Bounds.pts1.y = (SHORT)MarkerCoords[PointsToOutput].y;
                }
                else
                {
                    if ( Bounds.pts2.y <
                                     (SHORT)MarkerCoords[PointsToOutput].y )
                    {
                        Bounds.pts2.y = (SHORT)MarkerCoords[PointsToOutput].y;
                    }
                }
            } /* add in bounds for each point */

            /**************************************************************/
            /* Adjust local bounds for marker offsets from centre to edge */
            /**************************************************************/
            Bounds.pts1.x -= MarkerOffset.pts1.x;
            Bounds.pts2.x += MarkerOffset.pts2.x;
            Bounds.pts1.y -= MarkerOffset.pts1.y;
            Bounds.pts2.y += MarkerOffset.pts2.y;

            /**************************************************************/
            /* Update current bounds in the DC by adding in the bounds    */
            /* calculated for this operation                              */
            /**************************************************************/
            if ( FunNTest(COM_BOUND | COM_ALT_BOUND) )
            {
                eddg_AddBounds ((pDevRect)&Bounds,
                                FunN,
                                COORD_AI);
            }

#ifdef DCAF                                                                   //DCAF
            /**************************************************************/  //DCAF
            /* Accumulate DCAF screen bounds if required                  */  //DCAF
            /**************************************************************/  //DCAF
            if (DCAFBoundsRequired(FunN))                                     //DCAF
            {                                                                 //DCAF
                AccumulateScreenBoundsThroughClips( (pDevRect)&Bounds,        //DCAF
                                                    COORD_AI );               //DCAF
            }                                                                 //DCAF
#endif                                                                        //DCAF
        } /* bounds calculation */


        /******************************************************************/
        /* If correlation is needed and we have correlation rectangles    */
        /* then correlate on each of the marker boxes                     */
        /******************************************************************/
        if ( FunNTest(COM_CORRELATE) && (pdc->DCICorrNum) )
        {
            /**********************************************************/
            /* Correlate on each individual marker.  Include the      */
            /* initial point if this is the first time around the     */
            /* main loop.  Break out the loop as soon as a hit occurs */
            /**********************************************************/
            for ( PointsToOutput = (StartIndex == 0) ? (USHORT)0 : (USHORT)1;
                  PointsToOutput <= MarkersToOutput;
                  PointsToOutput++)
            {
               /***********************************************************/
               /* Get the rectangle defining the Marker                   */
               /***********************************************************/
               AIxfer.rcsTrg.pts1.x =
                ((SHORT)MarkerCoords[PointsToOutput].x) - MarkerOffset.pts1.x;
               AIxfer.rcsTrg.pts2.x =
                ((SHORT)MarkerCoords[PointsToOutput].x) + MarkerOffset.pts2.x;
               AIxfer.rcsTrg.pts1.y =
                ((SHORT)MarkerCoords[PointsToOutput].y) - MarkerOffset.pts1.y;
               AIxfer.rcsTrg.pts2.y =
                ((SHORT)MarkerCoords[PointsToOutput].y) + MarkerOffset.pts2.y;

               /***********************************************************/
               /* check if we correlate with this marker: exit if so      */
               /* (or if an error)                                        */
               /***********************************************************/
               if ( (ULONG)OK != (Result = (USHORT)eddg_CheckRectCorrelation(
                                           (pDevRect)&AIxfer.rcsTrg)) )
                   break;

            }

        } /* correlation */


        /**************************************************************/
        /* if software do exclusion test and disable cursor updates   */
        /**************************************************************/
        if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
        {
            eddm_ExcludeCursor((pDevPoint)&Bounds, COORD_AI);
        }

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

        /**************************************************************/
        /* set the colors and mixes - first check the hardware is     */
        /* free                                                       */
        /**************************************************************/
#ifndef   _8514
        ShadowXGARegs.FgCol = (USHORT)pdc->DCIMarkColatts.ForeColor;
        ShadowXGARegs.BgCol = (USHORT)pdc->DCIMarkColatts.BackColor;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;

        ShadowXGARegs.FgMix =
                        WinToXway[pdc->DCICurMrkAts.mbnd.usMixMode];
        ShadowXGARegs.BgMix =
                    WinToXway[pdc->DCICurMrkAts.mbnd.usBackMixMode];

#else
        #ifndef   BPP24
        Shadow8514Regs.Color_1 = (USHORT)pdc->DCIMarkColatts.ForeColor;
        Shadow8514Regs.Color_0 = (USHORT)pdc->DCIMarkColatts.BackColor;
        #else
        Shadow8514Regs.Color_1 = pdc->DCIMarkColatts.ForeColor;
        Shadow8514Regs.Color_0 = pdc->DCIMarkColatts.BackColor;
        #endif
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;

        Shadow8514Regs.Function_1.Mix =
                        WinToXway[pdc->DCICurMrkAts.mbnd.usMixMode];
        Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COL1;
        Shadow8514Regs.Function_0.Mix =
                    WinToXway[pdc->DCICurMrkAts.mbnd.usBackMixMode];
        Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COL0;
#endif

        TransferShadowRegisters(TSR_COLOUR_MIX);

        /**************************************************************/
        /* Output the markers stored in MarkerCoords (Include the     */
        /* first coordinate if this is the first time around the main */
        /* loop)                                                      */
        /**************************************************************/
        for ( PointsToOutput = (StartIndex == 0) ? (USHORT)0 : (USHORT)1;
              PointsToOutput <= MarkersToOutput;
              PointsToOutput++)
        {
            /**********************************************************/
            /* the blt pre-clipped target coordinates are the         */
            /* supplied position adjusted for the offsets from marker */
            /* centre We have the centre of the marker in h\w         */
            /* coordinates in MarkerCoords.  The adjustment from      */
            /* marker centre to the marker enclosing box (inclusive)  */
            /* is in MarkerOffsets.  The marker enclosing box is      */
            /* stored in blt parameter block as the target rectangle  */
            /**********************************************************/
            AIxfer.rcsTrg.pts1.x = ((SHORT)MarkerCoords[PointsToOutput].x) -
                                                  MarkerOffset.pts1.x;
            AIxfer.rcsTrg.pts2.x = ((SHORT)MarkerCoords[PointsToOutput].x) +
                                                  MarkerOffset.pts2.x;
            AIxfer.rcsTrg.pts1.y = ((SHORT)MarkerCoords[PointsToOutput].y) -
                                                  MarkerOffset.pts1.y;
            AIxfer.rcsTrg.pts2.y = ((SHORT)MarkerCoords[PointsToOutput].y) +
                                                  MarkerOffset.pts2.y;

            /**********************************************************/
            /* output the marker to the appropriate bitmap or screen  */
            /*                                                        */
            /**********************************************************/
            if ( FunNTest(COM_DRAW))
            {
                OutputMarker();
            }

        } /* for each marker after the first */

        /**************************************************************/
        /* mark the cursor for redrawing by checkcursor               */
        /**************************************************************/
        reenable_cursor();

#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 */

        /**************************************************************/
        /* Now move onto the next batch of markers.                   */
        /**************************************************************/
        MarkersLeft -= MarkersToOutput;
        StartIndex  += MarkersToOutput;
    }

    /******************************************************************/
    /* if we drew more than one marker then the current position is   */
    /* updated to be that of the last marker (1st marker is drawn at  */
    /* the current position)                                          */
    /******************************************************************/
    if ( NoOfPoints > 1 )
    {
        /**************************************************************/
        /* Update the current h/w position in the DC to be            */
        /* the last marker centre                                     */
        /**************************************************************/
        pdc->DCICurrPosAI.X =
                             (SHORT)MarkerCoords[MarkersToOutput - 1].x;
        pdc->DCICurrPosAI.Y =
                             (SHORT)MarkerCoords[MarkersToOutput - 1].y;

        /**************************************************************/
        /* Update the current world coordinate position               */
        /* if we were passed world coordinates then we can take this  */
        /* from the stack coordinate array (the pointer to this is    */
        /* currently one past the end of the array). If we have       */
        /* screen coordinates then we need to transform to device     */
        /* then to world                                              */
        /**************************************************************/
        if ( FunNTest(COM_TRANSFORM))
        {
            pdc->DCICurrPosWorld.x = Points[NoOfPoints-2].x;
            pdc->DCICurrPosWorld.y = Points[NoOfPoints-2].y;
        }

        else /* screen coordinates */
        {
            pdc->DCICurrPosWorld.x =
                    (SHORT)Points[NoOfPoints-2].x - pdc->DCIOrigin.X;
            pdc->DCICurrPosWorld.y =
                    (SHORT)Points[NoOfPoints-2].y - pdc->DCIOrigin.Y;

            if ( OK != EnginesDispatchTable[NGreConvert & 0xff](
                                       hdc,
                                       CVTC_DEVICE,
                                       CVTC_WORLD,
                                       (PPOINTL)&pdc->DCICurrPosWorld,
                                       1,
                                       0,
                                       NGreConvert) )
            {
                goto POLYMARKER_ERR_EXIT;
            }

        } /* convert screen to world current position */

    } /* update current position if more than one marker */


    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(Result);

POLYMARKER_ERR_EXIT:
    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD);

    return(ERROR_ZERO);

} /* eddb_PolyMarker */




VOID DRIVERCALL OutputMarker(VOID)
/**********************************************************************/
/* sets up the source and target coordinates for the blt of the       */
/* marker and calls the appropriate blt hardware interface            */
/**********************************************************************/
{
    /******************************************************************/
    /* set up source and target rectangles for the blt.               */
    /* The target is already initialised to be the marker box         */
    /* adjusted by the marker offsets (to allow for the position      */
    /* specifying the marker centre).                                 */
    /* If the target is clipped then a corresponding adjustment is    */
    /* made to the source                                             */
    /******************************************************************/

    /******************************************************************/
    /* first initialise the (pre-clipped) source blt coordinates.     */
    /* For the default set this is simply the marker dimensions.      */
    /* For a non default set, the font may be prop-spaced so we need  */
    /* to allow for left and right margins in setting up the blt      */
    /* dimensions (unlike the bitmap dimensions which are the cell    */
    /* dimensions).                                                   */
    /*                                                                */
    /* The margin values are held in the MARKER_INFO structure        */
    /* within the bitmap header.                                      */
    /*                                                                */
    /* Since the margins affect only the x dimension, the y dimension */
    /* is initialised later.                                          */
    /*                                                                */
    /* Note that if the set is not from a font then the margin values */
    /* will have been initialised to zero. (ie we will use the whole  */
    /* of the bitmap).                                                */
    /******************************************************************/
    AIxfer.rcsSrc.pts1.x = AIxfer.pbmhSrc->MarkerInfo.MarginWidth;
    AIxfer.rcsSrc.pts2.x = AIxfer.pbmhSrc->Info.HWWidth -
                           AIxfer.pbmhSrc->MarkerInfo.MarginHeight;

    /******************************************************************/
    /* blt source y coordinates are y dimensions of the marker bitmap */
    /* x dimension already set up                                     */
    /******************************************************************/
    AIxfer.rcsSrc.pts1.y = 0;
    AIxfer.rcsSrc.pts2.y = AIxfer.pbmhSrc->Info.HWHeight;

    /******************************************************************/
    /* the blt routines expect the target coordinates to be           */
    /* clipped to the target bitmap. Do this now.                     */
    /******************************************************************/
    if ( AIxfer.rcsTrg.pts1.y < 0 )
    {
        /**************************************************************/
        /* exit now if the top edge of target is below the bottom edge*/
        /**************************************************************/
        if ( AIxfer.rcsTrg.pts2.y < 0 )
        {
            return;
        }

        AIxfer.rcsSrc.pts1.y = AIxfer.rcsSrc.pts1.y - AIxfer.rcsTrg.pts1.y;
        AIxfer.rcsTrg.pts1.y = 0;

    }

    /******************************************************************/
    /* if the top edge of the target is above the bitmap then set the */
    /* top edge to the hardware height                                */
    /******************************************************************/
    if ( AIxfer.rcsTrg.pts2.y > AIxfer.pbmhDest->Info.HWHeight)
    {
        /**************************************************************/
        /* exit now if the bottom edge of target is also above edge   */
        /**************************************************************/
        if ( AIxfer.rcsTrg.pts1.y > AIxfer.pbmhDest->Info.HWHeight)
        {
            return;
        }

        AIxfer.rcsSrc.pts2.y = AIxfer.rcsSrc.pts2.y -
               (AIxfer.rcsTrg.pts2.y - AIxfer.pbmhDest->Info.HWHeight);
        AIxfer.rcsTrg.pts2.y = AIxfer.pbmhDest->Info.HWHeight;
    }

    if ( AIxfer.rcsTrg.pts1.x < 0 )
    {
        /**************************************************************/
        /* exit now if the right edge of target is to left of bitmap  */
        /**************************************************************/
        if ( AIxfer.rcsTrg.pts2.x < 0 )
        {
            return;
        }

        AIxfer.rcsSrc.pts1.x = AIxfer.rcsSrc.pts1.x - AIxfer.rcsTrg.pts1.x;
        AIxfer.rcsTrg.pts1.x = 0;

    }

    /******************************************************************/
    /* if the right edge of the target is to the right of the bitmap  */
    /* then set the right edge to be the bitmap hardware width        */
    /******************************************************************/
    if ( AIxfer.rcsTrg.pts2.x > AIxfer.pbmhDest->Info.HWWidth)
    {
        /**************************************************************/
        /* exit now if the left edge of target is also beyond edge    */
        /**************************************************************/
        if ( AIxfer.rcsTrg.pts1.x > AIxfer.pbmhDest->Info.HWWidth)
        {
            return;
        }

        AIxfer.rcsSrc.pts2.x = AIxfer.rcsSrc.pts2.x -
               (AIxfer.rcsTrg.pts2.x - AIxfer.pbmhDest->Info.HWWidth);
        AIxfer.rcsTrg.pts2.x = AIxfer.pbmhDest->Info.HWWidth;
    }

    /******************************************************************/
    /* set-up complete, so blt the source to the destination          */
    /******************************************************************/

    /******************************************************************/
    /* if we are in hardware drawing mode and the marker is not in    */
    /* VRAM then we will have to copy if to the PHUNK                 */
    /******************************************************************/
    if ( (!AIxfer.pbmhSrc->BMPhys) && !softDrawInUse)
    {
        eddb_PhunkThatBitmap(AIxfer.pbmhSrc);
    }

    /******************************************************************/
    /* set-up complete, so blt the source to the destination          */
    /******************************************************************/
    SPad.BltFunction = (*pDrawFunctions)[index_SrcDestBlt];
    PixBltThroughClips();

    /******************************************************************/
    /* If we copied the marker to the PHUNK then we must now unPHUNK  */
    /* it. All we have to do is invalidate its physical address.      */
    /******************************************************************/
    if ( AIxfer.pbmhSrc->BMPhys == pPhunkPhys )
    {
        AIxfer.pbmhSrc->BMPhys = FNULL;
    }

}
