/*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 = PRDBSETP
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdb_MixPel
 *             prdb_SetPel
 *
 * 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_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#define INCL_DDICOMFLAGS
#define INCL_DDIMISC
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS
#undef INCL_DDICOMFLAGS
#undef INCL_DDIMISC

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

#include <prdncone.h>

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

#include <prdbtyp1.h>
#include <prdbextf.h>
#include <prdcextf.h>
#include <prdgextf.h>
#include <prdiextf.h>
#include <prdnextf.h>
#include <prdncone.h>

/******************************************************************************/
/*  Set up external access to the default line attributes                     */
/******************************************************************************/
extern DLINEBUNDLE prda_DefLinAts;

/******************************************************************************/
/*  FUNCTION: prdb_MixPel                                                     */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  BitmapListEntry far *  ListEntry;  Pointer to list entry of bitmap to     */
/*                                     operate on                             */
/*  SHORT                 XCoord,     Coordinates of pel to mix              */
/*  SHORT                 YCoord;                                            */
/*  BYTE                   AtsColor;   Colour and ...                         */
/*  WORD                   AtsMix;     ... mix attributes to use              */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function sets the specified pel to the correct value taking account  */
/*  of its current attributes and the mix required.                           */
/******************************************************************************/
void prdb_MixPel( BitmapListEntry *ListEntry,
                  USHORT           XCoord,
                  USHORT           YCoord,
                  BYTE             AtsColor,
                  USHORT           AtsMix )

{
#define TFUNC "prdb_Mixpel"

    /**************************************************************************/
    /*  Local Variables                                                       */
    /**************************************************************************/
    BYTE    Mask;                      /* Mask for writing a pel to a byte    */
    BYTE    Dest;                      /* The result of the mix               */
    BYTE    BMByte;                    /* The byte from the bitmap to for the */
                                       /* pel we are mixing                   */
    ULONG   ByteOffset;                /* Byte offset to bitmap               */
    USHORT  BitOffset;                 /* Offset within bitmap byte           */
    USHORT  Bitcount;                  /* The number of bitmap bits per pel   */
                                       /* for this format                     */

    /**************************************************************************/
    /*  Work out where in the bitmap the bits for this pel position are - use */
    /*  GetOffsets.                                                           */
    /**************************************************************************/
    (VOID)prdb_GetOffsets(ListEntry, XCoord, YCoord, &ByteOffset, &BitOffset);

    /**************************************************************************/
    /*  Now do the mix - (1,1) and (4,1) formats are supported:               */
    /*      Source = pel set to foreground color                              */
    /*      Dest   = pel before mix                                           */
    /*      Mask   = mask for writing the pel to the byte                     */
    /*  The source and destination are manipulated at the position within the */
    /*  byte where they occur and are then written back to the bitmap using   */
    /*  the mask.                                                             */
    /**************************************************************************/
    if ((Bitcount = (USHORT)(ListEntry->Parms.Bitcount)) > 4)
        Mask = 0xff;
    else
        if (Bitcount == 4)
        {
            BitOffset -= 3;
            Mask = (BYTE)0x0f << BitOffset;
        }
        else
            Mask = (BYTE)0x01 << BitOffset;

    /**************************************************************************/
    /*  Fetch the byte from the bitmap allowing for huge bitmaps.             */
    /**************************************************************************/
    if (ListEntry->Huge == 0)
    {
        BMByte = ((ListEntry->Bitmap)[ByteOffset]);
    }
    else
    {
        BMByte = (prdb_HugeGetByte(ListEntry->Bitmap, ByteOffset));
    }
    switch (AtsMix)

    /**************************************************************************/
    /*  Switch depending on the mix.                                          */
    /**************************************************************************/
    {
    case (USHORT)FM_DEFAULT:

        /**********************************************************************/
        /*  Default case - do a FM_OVERPAINT                                  */
        /**********************************************************************/
        Dest = (AtsColor << BitOffset);
        break;
    case (USHORT)FM_OR:
        Dest = (AtsColor << BitOffset) | BMByte;
        break;
    case (USHORT)FM_OVERPAINT:
        Dest = (AtsColor << BitOffset);
        break;
    case 0x0003:

        /**********************************************************************/
        /*  This should not occur - do a FM_LEAVEALONE                        */
        /**********************************************************************/
        Dest = BMByte;
        break;
    case (USHORT)FM_XOR:
        Dest = (AtsColor << BitOffset) ^ BMByte;
        break;
    case (USHORT)FM_LEAVEALONE:
        Dest = BMByte;
        break;
    case (USHORT)FM_AND:
        Dest = (AtsColor << BitOffset) & BMByte;
        break;
    case (USHORT)FM_SUBTRACT:
        Dest = (~(AtsColor << BitOffset)) & BMByte;
        break;
    case (USHORT)FM_MASKSRCNOT:
        Dest = (AtsColor << BitOffset) & (~BMByte);
        break;
    case (USHORT)FM_ZERO:
        Dest = 0;
        break;
    case (USHORT)FM_NOTMERGESRC:
        Dest = ~((AtsColor << BitOffset) | BMByte);
        break;
    case (USHORT)FM_NOTXORSRC:
        Dest = ~((AtsColor << BitOffset) ^ BMByte);
        break;
    case (USHORT)FM_INVERT:
        Dest = ~BMByte;
        break;
    case (USHORT)FM_MERGESRCNOT:
        Dest = (AtsColor << BitOffset) | (~BMByte);
        break;
    case (USHORT)FM_NOTCOPYSRC:
        Dest = ~(AtsColor << BitOffset);
        break;
    case (USHORT)FM_MERGENOTSRC:
        Dest = ~((AtsColor << BitOffset)) | BMByte;
        break;
    case (USHORT)FM_NOTMASKSRC:
        Dest = ~((AtsColor << BitOffset) & BMByte);
        break;
    case (USHORT)FM_ONE:
        Dest = 0xff;
        break;
    default:

        /**********************************************************************/
        /*  For an undefined mix do a FM_LEAVEALONE.                          */
        /**********************************************************************/
        Dest = BMByte;
        break;
    }

    /**************************************************************************/
    /*  Write only the pel we are mixing to the destination.                  */
    /**************************************************************************/
    Dest = (BMByte & (~Mask)) | (Dest & Mask);

    /**************************************************************************/
    /*  Put the new byte back in the bitmap allowing for a huge bitmap.       */
    /**************************************************************************/
    if (ListEntry->Huge == 0)
    {
        (ListEntry->Bitmap)[ByteOffset] = Dest;
    }
    else
    {
        (VOID)prdb_HugeSetByte(ListEntry->Bitmap, ByteOffset, Dest);
    }
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prdb_SetPel                                                     */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  See "OS/2 Technical Reference: I/O Subsytems and Device Drivers"          */
/*                                                                            */
/*  hanDC   DcH;                                                              */
/*  PULONG  ArgParm;                                                          */
/*  lpDCI   DCIData;                                                          */
/*  ULONG   FunN;                                                             */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function sets the pel specified by ArgParm in the currently selected */
/*  bitmap.  It does the necessary transformations, bounds accumulation and   */
/*  clipping.                                                                 */
/******************************************************************************/
ULONG EXPENTRY prdb_SetPel( hanDC      DcH,
                            PULONG     ArgParm,
                            lpDCI      DCIData,
                            ULONG      FunN )

{
#define TFUNC "prdb_SetPel"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    ULONG                Command;      /* Command part of FunN                */
/*  BitmapListEntry far *ListEntry; */ /* Bitmap list entry pointer device    */
                                                                   /* CON3201 */
    BitmapListEntry     *ListEntry;    /* Bitmap list entry pointer device    */
                                       /* coordinates                         */
    DevPoint             lcCoord;      /* Coordinates of the pel in device    */
                                       /* coordinates                         */
    DevRect              BoundsRect;   /* Bounding rectangle for passing to   */
                                       /* prdg_AddBounds                      */
    DevRect              lcClipReg;    /* Current clip rectangle.             */
    USHORT                i;            /* Loop control variable               */
    BYTE                 PelColor;     /* Pel color (bits)                    */
    USHORT               PelMix;       /* Pel foreground mix                  */
    SHORT                Result;
    RECTL                BoundsRectL;  /* Bounds for clipping processing      */

    TRACE8("prdbsetp", "Command", &Command, 1);

    /**************************************************************************/
    /*  TRACE the input parameters                                            */
    /**************************************************************************/
    TRACE8("prdbsetp", "FunN",  &FunN, 1);
    TRACE8("prdbsetp", "DcH",   &DcH, 1);
    TRACE8("prdbsetp", "DCIData",  &DCIData, 1);
    TRACE8("prdbsetp", "Parms",  ArgParm, 2);

    /**************************************************************************/
    /*  Extract the command flags from the function and check for area and    */
    /*  path validity.                                                        */
    /**************************************************************************/
//  Command = ((PULONG)(&FunN))[1] & DCIData->CommandMask;
    Command = FunN & DCIData->CommandMask;
    prdm_ValidateArea;
    prdm_ValidatePath;

    /**************************************************************************/
    /*  Make sure there is a bitmap selected for this DC - this will either be*/
    /*  a Memory or Direct DC - and get the list entry pointer.               */
    /**************************************************************************/
 /* if (!((PBYTE)ListEntry = DCIData->DCISelBitmap)) */
    if (!(ListEntry = (pBMListEntry)DCIData->DCISelBitmap))        /* CON3201 */
    {
        LOGERR(TFUNC, "No Bitmap", FNULL, 0,PMERR_NO_BITMAP_SELECTED);
        return (ERROR_ZERO);
    }
#ifdef PRD_TIMING
    DEKHOOK0(A,7,2B)
#endif
    prdm_EnterDriver(DCIData);

    /**************************************************************************/
    /*  Set the device text only flag to FALSE since we're about to draw into */
    /*  the band.                                                             */
    /**************************************************************************/
    DCIData->TextOnlyDC = FALSE;

    /**************************************************************************/
    /*  Do the new framework drawing function - sets DRAWN_INTO flag if       */
    /*  COM_DRAW is set.  Returns error if not in a suitable state.           */
    /**************************************************************************/
    if ((Result = prdn_CheckDrawingState(&Command, DCIData)) != OK)
    {
        prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,7,AB)
#endif
        return((Result==ERR_PURGE) ? OK : ERROR_ZERO);
    }

    /**************************************************************************/
    /*  Got the correct bitmap list entry - transform from world to device    */
    /*  coordinates                                                           */
    /**************************************************************************/
 /* if (prdg_FastConvert((WcsPoint far *)ArgParm,                       */
 /*                      (DevPoint far *)&lcCoord, DcH, Command) != OK) */
    if (prdg_FastConvert((WcsPoint *)ArgParm,                        /*CON3201*/
                         (DevPoint *)&lcCoord, DcH, Command) != OK)  /*CON3201*/
    {
        TRACE4("prdbsetp", "Convert failed", FNULL, 0);
        prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,7,AB)
#endif
        return(ERROR_ZERO);
    }
    TRACE4("prdbsetp", "Coords X,Y", &lcCoord, 1);

    /**************************************************************************/
    /*  If bounds determination required then accumulate bounds               */
    /**************************************************************************/
    TRACE4("prdbsetp", "Command", &Command, 1);
    if ((Command & COM_BOUND) != 0)
    {
        BoundsRect[0].X = lcCoord.X;
        BoundsRect[1].X = lcCoord.X;
        BoundsRect[0].Y = lcCoord.Y;
        BoundsRect[1].Y = lcCoord.Y;
     /* (VOID)prdg_AddBounds((DevRect far *) BoundsRect, DCIData); */
        (VOID)prdg_AddBounds((DevRect *) BoundsRect, DCIData);     /* CON3201 */
    }

    /**************************************************************************/
    /*  First-level checks have been completed, and Bounds have been          */
    /*  calculated (if required).  So if the COM_DRAW is not set then we can  */
    /*  exit OK.                                                              */
    /**************************************************************************/
    if ((Command & COM_DRAW) == 0)
    {
        TRACE4("prdbsetp", "No Draw Bit", &Command, 1);
        prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,7,AB)
#endif
        return(OK);
    }

    /**************************************************************************/
    /*  Establish pel color and mix from the current line attributes (or the  */
    /*  defaults).                                                            */
    /**************************************************************************/
    PelColor = prdc_ColorToPelBits(DCIData->DCICurLinAts->lbnd.lColor,
                                   DCIData, ListEntry->DCTPtr);
    PelMix = DCIData->DCICurLinAts->lbnd.usMixMode;
    if (PelMix == 0)
        PelMix = prda_DefLinAts.lbnd.usMixMode;

    /**************************************************************************/
    /*  PD00267 : Pick up the bounding rectangle for the image and pass it to */
    /*  prdi_GetNextClip().                                                   */
    /**************************************************************************/
    BoundsRectL.xLeft   = (ULONG)lcCoord.X;
    BoundsRectL.yBottom = (ULONG)lcCoord.Y;
    BoundsRectL.xRight  = (ULONG)lcCoord.X + 2; /* PD00308...                 */
    BoundsRectL.yTop    = (ULONG)lcCoord.Y + 2; /* PD00308...                 */

    /**************************************************************************/
    /*  For every valid clip rectangle returned by prdi_GetNextClip try the   */
    /*  pel against it and if it is inside mix it and break from the loop.    */
    /**************************************************************************/
 /* for (i = 1; prdi_GetNextClip(DCIData, i,(DevRect far*)lcClipReg, */
    for (i = 1; prdi_GetNextClip(DCIData, i,(DevRect *)lcClipReg,  /* CON3201 */
                                 &BoundsRectL) == OK; i++)
    {
        TRACE4("prdbsetp", "first clip rect", NULL, 0);
        if ((lcCoord.X < lcClipReg[0].X) || (lcCoord.X >= lcClipReg[1].X) ||
            (lcCoord.Y < lcClipReg[0].Y) || (lcCoord.Y >= lcClipReg[1].Y))
        {

            /******************************************************************/
            /*  The pel is outside - try another clip rectangle.              */
            /******************************************************************/
            TRACE4("prdbsetp", "pel outside band", NULL, 0);
            continue;
        }

        /**********************************************************************/
        /*  The pel is inside - mix it and break out of the loop.             */
        /**********************************************************************/
        (VOID)prdb_MixPel(ListEntry, lcCoord.X, lcCoord.Y, PelColor, PelMix);
        break;
    }
    prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,7,AB)
#endif
    return (OK);
}
#undef TFUNC
