/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDLSUBR
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdl_LineSetUp
 *             Bresenham
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_GPIERRORS
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS

#define INCL_DDIMISC
#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#include <pmddi.h>
#undef INCL_DDIMISC
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL

#include <prdlcone.h>

#include <prdltypt.h>

#include <prdcextf.h>
#include <prdlextf.h>




/**********************************************************************/
/* Set up access to the default line attributes an the linetype table */
/**********************************************************************/
extern USHORT       LineTypeTable [];
extern DLINEBUNDLE  prda_DefLinAts;
extern USHORT       prdd_HugeInc;


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdl_LineSetUp                                         */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   pBMListEntry far *pListEntry; Pointer to bitmap list entry       */
/*   PBYTE             pColor;     Pointer to foreground colour       */
/*   PUSHORT           pMix;       Pointer to foreground mix          */
/*   PUSHORT           pType;      Pointer to line type               */
/*   PUSHORT           pMask;      Pointer to line type mask pointer  */
/*   lpDCI             DCIData;    Pointer to DC Instance data        */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function returns, via the pointers passed to it, the bit    */
/*   map list entry, color, mix, line type and line type mask from    */
/*   the current line attributes (or the default line attributes)     */
/*   in the DC Instance data.                                         */
/*                                                                    */
/**********************************************************************/
#if 0
USHORT pascal prdl_LineSetUp (pListEntry, pColor, pMix, pType,
                            pMask, DCIData)

pBMListEntry far * pListEntry;
PBYTE              pColor;
PUSHORT            pMix;
PUSHORT            pType;
PUSHORT FAR *      pMask;
lpDCI              DCIData;
#endif

USHORT prdl_LineSetUp ( pBMListEntry *pListEntry,          /* CON3201 */
                        PBYTE         pColor,              /* CON3201 */
                        PUSHORT       pMix,                /* CON3201 */
                        PUSHORT       pType,               /* CON3201 */
                        PUSHORT      *pMask,               /* CON3201 */
                        lpDCI         DCIData )            /* CON3201 */

{
#define TFUNC "prdl_LineSetUp"
    /******************************************************************/
    /* Make sure there is a bitmap selected for this DC               */
    /******************************************************************/
    if ( !(*pListEntry = (pBMListEntry)DCIData->DCISelBitmap) )
    {
        LOGERR(TFUNC, "No Bitmap", FNULL, 0,PMERR_NO_BITMAP_SELECTED);
        return (ERROR_ZERO);
    }

    /******************************************************************/
    /* Establish line color and mix                                  */
    /******************************************************************/
    *pColor = prdc_ColorToPelBits(DCIData->DCICurLinAts->lbnd.lColor,
                                  DCIData,
                                  (*pListEntry)->DCTPtr);
    *pMix = DCIData->DCICurLinAts->lbnd.usMixMode;

    /******************************************************************/
    /* If linetype is default then work out what the default is and   */
    /* use as index into LineTypeTable. Also use the default if       */
    /* the line type is not in the range 0 - (NUMBER_LINETYPES-1)     */
    /******************************************************************/
    if ((DCIData->DCICurLinAts->lbnd.usType == 0) ||
        (DCIData->DCICurLinAts->lbnd.usType >= NUMBER_LINETYPES))
        *pType = LineTypeTable [prda_DefLinAts.lbnd.usType];
    else
        *pType = LineTypeTable [DCIData->DCICurLinAts->lbnd.usType];

    /******************************************************************/
    /* Set up a pointer to the line type mask.                        */
    /******************************************************************/
    *pMask = (PUSHORT)&DCIData->DCILineTypMask;

    return(OK);
}
#undef TFUNC


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: Bresenham                                              */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   BitmapListEntry far *ListEntry;   The selected bitmap            */
/*   DevPoint             Start;       Start and ...                  */
/*   DevPoint             End;         ... end coordinates of line    */
/*   BYTE                 LineColor;   Color,                         */
/*   USHORT               LineMix;       mix,                         */
/*   USHORT               LineType;      line type,                   */
/*   PUSHORT              pMask;         and a pointer to the line    */
/*                                       type mask to use             */
/*   USHORT               LastStep;    Flag for whether or not last   */
/*                                     pel should be set              */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   Function calculates series of coordinates for points to make up  */
/*   a straight line from Start to End using Bresenham's algorithm.   */
/*                                                                    */
/*   CHANGES:                                                         */
/*                                                                    */
/*   Note that this function does not implement line styling instead  */
/*   it relies on a mask which is shifted after every pel.            */
/*                                                                    */
/*   REFERENCE:                                                       */
/*                                                                    */
/*   The algorithm used here is an extended version of the one        */
/*   described in 'Principles of Interactive Computer Graphics' by    */
/*   W. M. Newman and R. F. Sproull pub. McGraw-Hill.                 */
/*                                                                    */
/*   It has been extended to allow for:                               */
/*        - delta y > delta x                                         */
/*        - either delta y or delta x < 0                             */
/*                                                                    */
/*   It uses only integer arithmetic.                                 */
/*                                                                    */
/**********************************************************************/
#if 0
void pascal Bresenham (ListEntry, Start, End, LineColor, LineMix,
                       LineType, pMask, LastStep)

BitmapListEntry far *ListEntry;
DevPoint             Start;
DevPoint             End;
BYTE                 LineColor;
USHORT               LineMix;
USHORT               LineType;
PUSHORT              pMask;
USHORT               LastStep;
#endif

void Bresenham ( BitmapListEntry *ListEntry,               /* CON3201 */
                 DevPoint         Start,                   /* CON3201 */
                 DevPoint         End,                     /* CON3201 */
                 BYTE             LineColor,               /* CON3201 */
                 USHORT           LineMix,                 /* CON3201 */
                 USHORT           LineType,                /* CON3201 */
                 PUSHORT          pMask,                   /* CON3201 */
                 USHORT           LastStep )               /* CON3201 */

{
#define TFUNC "Bresenham"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    int      DeltaX;                   /* Difference between x values */
    int      DeltaY;                   /* Difference between y values */
    int      absDeltaX;                /* Abs. diff. between x values */
    int      absDeltaY;                /* Abs. diff. between y values */
    int      NumberOfSteps;            /* The number of steps in the  */
                                       /* line                        */
    int      ErrorTerm;                /* The error term from         */
                                       /* Bresenhams algorithm        */
    int      ErrorTermIncrement;       /* The increment which is      */
                                       /* applied to the error term   */
                                       /* after each iteration where  */
                                       /* there is no increment in the*/
                                       /* minor axis                  */
    int      ErrorTermDecrement;       /* The decrement which is      */
                                       /* applied to the error term   */
                                       /* after each iteration where  */
                                       /* there is an increment in the*/
                                       /* minor axis                  */
/*  BYTE     DiagonalRatio;    PF */   /* style ratio diagonal (x+y)  */
/*  BYTE     StyleMask;        PF */   /* style number low byte       */
/*  PBYTE    StyleError;       PF */   /* style number high byte      */
    ULONG                ByteOffset;   /* Byte offset into bitmap to  */
                                       /* current byte                */
    register USHORT      BitOffset;    /* Offset within bitmap byte   */
                                       /* to current pel              */
    register USHORT      BitCount;     /* Number of bits per pel (for */
                                       /* a monochrome printer this   */
                                       /* will be 1)                  */
    SHORT                BitOffsetStart;/* The offset in bits into the*/
                                       /* first pel in a byte in the  */
                                       /* bitmap (this will depend on */
                                       /* the direction we are drawing*/
                                       /* the line in)                */
    SHORT                BitOffsetReset;/* The offset in bits into the*/
                                       /* last pel in a byte in the   */
                                       /* bitmap (this will depend on */
                                       /* the direction we are drawing*/
                                       /* the line in)                */
    SHORT                ByteOffsetInc ;/* +/- 1 depending on the     */
                                       /* direction we are drawing in */
    SHORT                BitOffsetInc; /* +/- the number of bits per  */
                                       /* pel                         */
    SHORT                BytesPerRow;  /* The number of bytes per row */
                                       /* in the bitmap we are drawing*/
                                       /* into                        */
    BOOL                 XMove;        /* TRUE if moving in the x     */
                                       /* direction                   */
    PBYTE                BLEBitmap;    /* Pointer to the bitmap       */
    BYTE                 Mask;         /* The mask to allow us to     */
                                       /* manipulate one pel at a time*/
    BYTE                 StartMask;    /* Mask for when the bit offset*/
                                       /* is 0                        */
    BYTE                 Dest;         /* The 'destination' used to   */
                                       /* build up the pel to insert  */
                                       /* into the bitmap             */
    BYTE                 BMByte;       /* The current bitmap byte     */
    PBYTE                BMAddress;    /* Pointer to current position */
                                       /* in the bitmap               */

    /******************************************************************/
    /* Initialise variables and determine what the major axis is for  */
    /* the line.                                                      */
    /******************************************************************/
    DeltaX = (int) End.X - (int) Start.X;
    DeltaY = (int) End.Y - (int) Start.Y;
    XMove = ((absDeltaX = abs(DeltaX)) >= (absDeltaY = abs(DeltaY)));

    /******************************************************************/
    /* Set up BitCount and BytesPerRow and calculate position in      */
    /* bitmap to start from.                                          */
    /******************************************************************/
    BitCount = (USHORT)ListEntry->Parms.Bitcount;
    BytesPerRow = (USHORT)ListEntry->Parms.BytesPerRow;
    TRACE4(TFUNC, "BytesPerRow", &BytesPerRow, 1);
    BitOffset = 7 - ((Start.X * BitCount) & 0x07);
    ByteOffset = ( (ULONG)BytesPerRow *
                   (ULONG)Start.Y ) +
                 ( ( (ULONG)BitCount *
                     (ULONG)Start.X ) /8L );
    TRACE4(TFUNC, "byteoffset", &ByteOffset, 1);
    /******************************************************************/
    /* Set up the Mask, StartMask, BitOffsetReset, BitOffsetStart,    */
    /* ByteOffsetInc and BitOffsetInc.  These values will depend on   */
    /* the x direction the line is going in.                          */
    /******************************************************************/
    if (BitCount == 1)
    {
        Mask = (StartMask = (BYTE)0x01) << BitOffset;
        if (DeltaX < 0)
        {
            BitOffsetReset = 7;
            BitOffsetStart = 0;
            ByteOffsetInc = -1;
            BitOffsetInc = 1;
        }
        else
        {
            BitOffsetReset = 0;
            BitOffsetStart = 7;
            ByteOffsetInc = 1;
            BitOffsetInc = -1;
        }
    }
    /*.. if (BitCount == 1) ..........................................*/

    else
    {
        BitOffset -= 3;
        Mask = (StartMask = (BYTE)0x0f) << BitOffset;
        if (DeltaX < 0)
        {
            BitOffsetReset = 4;
            BitOffsetStart = 0;
            ByteOffsetInc = -1;
            BitOffsetInc = 4;
        }
        else
        {
            BitOffsetReset = 0;
            BitOffsetStart = 4;
            ByteOffsetInc = 1;
            BitOffsetInc = -4;
        }
    }
    /*.. else ! (BitCount == 1) ......................................*/

    /******************************************************************/
    /* Initialize BLEBitmap and set up BMAddress to point             */
    /* to the first byte in the bitmap we need to access allowing for */
    /* a huge increment.                                              */
    /******************************************************************/
    BLEBitmap = ListEntry->Bitmap;
/*  prdm_GetByte;   CON3201 */
    BMAddress = BLEBitmap + ByteOffset;
    BMByte = *BMAddress;

    /******************************************************************/
    /* Make bytes per row negative if the line is going down, ie.     */
    /* move 'down' through the bitmap (the first byte of the bitmap   */
    /* is the bottom left)                                            */
    /******************************************************************/
    if (DeltaY < 0)                  /*   if line going down          */
        BytesPerRow = -BytesPerRow;  /* byte offset will be dcrmntd   */

    /******************************************************************/
    /* Initialise some local variables holding the style information  */
    /******************************************************************/
/*  DiagonalRatio = DCIData->StyleXRatio + DCIData->StyleYRatio;
    StyleMask  =   (PBYTE)(&DCIData->StyleNumber);
    StyleError = &((PBYTE)(&DCIData->StyleNumber))[1];
    TRACE4(TFUNC, "Starting mask", StyleMask, 1);     PF      */

    /******************************************************************/
    /* Set up the NumberOfSteps, the ErrorTermIncrement, the          */
    /* ErrorTermDecrement and the inital ErrorTerm all of which will  */
    /* depend on which is the major axis of the line.                 */
    /******************************************************************/
    if (XMove)
    {
        /**************************************************************/
        /* The major axis is the x axis                               */
        /**************************************************************/
        NumberOfSteps = absDeltaX;
        ErrorTermIncrement = 2 * absDeltaY;
/*      StyleErrorDecrement = DCIData->StyleXRatio;          PF */
    }
    else
    {
        /**************************************************************/
        /* The major axis is the y axis                               */
        /**************************************************************/
        NumberOfSteps = absDeltaY;
        ErrorTermIncrement = 2 * absDeltaX;
/*      StyleErrorDecrement = DCIData->StyleYRatio;          PF */
    }

    /******************************************************************/
    /* If the 'line' is actually a single pel and we are not to draw  */
    /* the last pel then exit                                         */
    /******************************************************************/
    if (NumberOfSteps < LastStep)
        return;
    ErrorTerm = ErrorTermIncrement - NumberOfSteps;
    ErrorTermDecrement = 2 * NumberOfSteps - ErrorTermIncrement;

    /******************************************************************/
    /* Loop around drawing pels and updating the position in the      */
    /* bitmap until there are no more pels to draw (exit is via a     */
    /* break from the middle of the loop.                             */
    /******************************************************************/
    for(;;)
    {
        TRACE4(TFUNC,"LineType",&LineType,1);
        TRACE4(TFUNC,"pMask",pMask,1);
        if((LineType & *pMask) != 0)
/*      if ((*StyleMask & 0x80) != 0)         PF   */
        {
        TRACE4(TFUNC,"BMByte",&BMByte,1);
        TRACE4(TFUNC,"BMAddress",&BMAddress,1);
            /**********************************************************/
            /* If the next pel should be on in the current linetype   */
            /* then draw it.  Switch according to the line mix and    */
            /* perform the appropriate operation.                     */
            /**********************************************************/
            switch (LineMix)
            {
            case (USHORT)FM_OR:
                Dest = (LineColor << BitOffset) | BMByte;
                break;
            case (USHORT)FM_OVERPAINT:
            case (USHORT)FM_DEFAULT:
                Dest = (LineColor << BitOffset);
                break;
            case (USHORT)FM_XOR:
                Dest = (LineColor << BitOffset) ^ BMByte;
                break;
            case (USHORT)FM_LEAVEALONE:
                Dest = BMByte;
                break;
            case (USHORT)FM_AND:
                Dest = (LineColor << BitOffset) & BMByte;
                break;
            case (USHORT)FM_SUBTRACT:
                Dest = (~LineColor) << BitOffset & BMByte;
                break;
            case (USHORT)FM_MASKSRCNOT:
                Dest = (LineColor << BitOffset) & (~BMByte);
                break;
            case (USHORT)FM_ZERO:
                Dest = 0;
                break;
            case (USHORT)FM_NOTMERGESRC:
                Dest = ~((LineColor << BitOffset) | BMByte);
                break;
            case (USHORT)FM_NOTXORSRC:
                Dest = ~((LineColor << BitOffset) ^ BMByte);
                break;
            case (USHORT)FM_INVERT:
                Dest = ~BMByte;
                break;
            case (USHORT)FM_MERGESRCNOT:
                Dest = (LineColor << BitOffset) | (~BMByte);
                break;
            case (USHORT)FM_NOTCOPYSRC:
                Dest = ~(LineColor << BitOffset);
                break;
            case (USHORT)FM_MERGENOTSRC:
                Dest = ~(LineColor) << BitOffset | BMByte;
                break;
            case (USHORT)FM_NOTMASKSRC:
                Dest = ~((LineColor << BitOffset) & BMByte);
                break;
            case (USHORT)FM_ONE:
                Dest = 0xff;
                break;
            }
            /*.. switch (LineMix) ....................................*/

            /**********************************************************/
            /* Replace current pel in bitmap with new one.            */
            /**********************************************************/
            *BMAddress = (BMByte = (BMByte & (~Mask)) | (Dest & Mask));
        }
        /*.. if((LineType & *pMask) != 0) ...pel is on in line style..*/

        /**************************************************************/
        /* Advance the linetype mask one position and reset if        */
        /* necessary.                                                 */
        /**************************************************************/
        if (*pMask & 0x0001)
            *pMask = 0x8000;
        else
            *pMask >>= 1;

        /**************************************************************/
        /* If we should not print any more steps (allowing for not    */
        /* printing last pel if specified) then exit the loop.        */
        /**************************************************************/
        if (NumberOfSteps-- == LastStep)
            break;

        if (XMove)
        {
            /**********************************************************/
            /* If the x axis is the major axis                        */
            /**********************************************************/

            if (BitOffset == BitOffsetReset)
            {
                /******************************************************/
                /* If we need to reset the BitOffset because it is    */
                /* currently pointing to the last bit in the current  */
                /* byte then do so and update the ErrorTerm and the   */
                /* ByteOffset (making a move in the y direction if    */
                /* required by the ErrorTerm) and fetch the next byte */
                /* from the bitmap.                                   */
                /******************************************************/
                TRACE4(TFUNC,"reset offset",&BitOffsetReset,1);
                BitOffset = BitOffsetStart;
                if (ErrorTerm > 0)
                {
                    ByteOffset =
                               ByteOffset + BytesPerRow + ByteOffsetInc;
                    ErrorTerm = ErrorTerm - ErrorTermDecrement;
                }
                else
                {
                    ErrorTerm = ErrorTerm + ErrorTermIncrement;
                    ByteOffset += ByteOffsetInc;
                }
                /******************************************************/
                /* prdm_GetByte is a macro which will fetch the       */
                /* current byte from the bitmap                       */
                /******************************************************/
/*              prdm_GetByte;    CON3201 */
                BMAddress = BLEBitmap + ByteOffset;
                BMByte = *BMAddress;
            }
            /*.. if (BitOffset == BitOffsetReset) ....................*/

            else
            {
                /******************************************************/
                /* Otherwise just increment the BitOffset and update  */
                /* the ErrorTerm and (if necessary - depending on     */
                /* ErrorTerm) update the ByteOffset into the bitmap   */
                /* and fetch the required byte (ie if we have made a  */
                /* move in the y direction).                          */
                /******************************************************/
                TRACE4(TFUNC,"no reset offset",&BitOffsetReset,1);
                BitOffset += BitOffsetInc;
                if (ErrorTerm > 0)
                {
                    ByteOffset += BytesPerRow;
/*                  prdm_GetByte;     CON3201 */
                    BMAddress = BLEBitmap + ByteOffset;
                    BMByte = *BMAddress;
                    ErrorTerm = ErrorTerm - ErrorTermDecrement;
                }
                else
                    ErrorTerm = ErrorTerm + ErrorTermIncrement;
            }
            /*.. else ! (BitOffset == BitOffsetReset) ................*/

            Mask = StartMask << BitOffset;
        }
        /*.. if (XMove) ..............................................*/

        else
        {

            /**********************************************************/
            /* If the y axis is the major axis.                       */
            /**********************************************************/

            if (ErrorTerm > 0)
            {
                /******************************************************/
                /* If we need to make a move in the x axis then update*/
                /* the ErrorTerm, update the BitOffset (allowing for  */
                /* a reset) and update the byte offset for the        */
                /* move in the y axis.                                */
                /******************************************************/
                ErrorTerm = ErrorTerm - ErrorTermDecrement;
                if (BitOffset == BitOffsetReset)
                {
                    BitOffset = BitOffsetStart;
                    ByteOffset =
                               ByteOffset + BytesPerRow + ByteOffsetInc;
                }
                else
                {
                    BitOffset += BitOffsetInc;
                    ByteOffset += BytesPerRow;
                }
                Mask = StartMask << BitOffset;
            }
            /*.. if (ErrorTerm > 0) ..................................*/

            else
            {
                /******************************************************/
                /* Otherwise update the ErrorTerm and make the        */
                /* constant move in the y axis.                       */
                /******************************************************/
                ByteOffset += BytesPerRow;
                ErrorTerm = ErrorTerm + ErrorTermIncrement;
            } /* ErrorTerm <= 0 */
            /**********************************************************/
            /* Get the next byte from the bitmap (this is always      */
            /* necessary when the major axis is the y axis.           */
            /**********************************************************/
/*          prdm_GetByte;  CON3201 */
            BMAddress = BLEBitmap + ByteOffset;
            BMByte = *BMAddress;
        }
        /*.. else ! (XMove) ..........................................*/

    }
    /*.. for(;;) .....................................................*/


} /* Bresenham */
#undef TFUNC



