/*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          = EDDBIMAG                                       */
/*                                                                    */
/*   Description     = Display Device Driver Minor Function :         */
/*                     ImageData                                      */
/*                                                                    */
/*   Function        = ImageData draws a single row of data using the */
/*                     current image colours and mixes.               */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_DDIPATHS
#define INCL_DDIMISC
#include <eddinclt.h>

#include <eddbcone.h>
#include <eddmcone.h>

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

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

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

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

/**********************************************************************/
/* EXTERNALS                                                          */
/**********************************************************************/
extern BYTE                     WinToXway[];

#ifndef   _8514
extern MMReg               ShadowXGARegs;
extern pMMReg              pXGARegs;
extern pMMReg              pRealXGARegs;
#else
#include <8514.h>
extern MM8514Reg                Shadow8514Regs;
extern pMM8514Reg               p8514Regs;
#endif

extern IMAGEDATAPB              AIxfer;

extern ClipRectangle            GetClipsBounds;
extern CURSORDATA               cursor_data;

extern SHORT                    softDrawInUse;

extern ULONG                    pPhunkPhys;
extern PVOID                    pPhunkVirt;

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

extern pDrawFunctionsTable      pDrawFunctions;


/**********************************************************************/
/*   ImageData draws a single row of data.  The engine                */
/* supplies a given number of pels at one bit/pel.  `1' bits are      */
/* drawn using the current image foreground colour and mix; `0'       */
/* bits are drawn using the background colour and mix.                */
/*                                                                    */
/*   The row in the bitmap the data is drawn into is given relative   */
/* to the current position; `row 0' means the row which include the   */
/* current position and the row number increases downward.            */
/*                                                                    */
/* The current position remains unaltered.                            */
/**********************************************************************/

DDIENTRY eddb_ImageData (HDC           hdc,
                         PBYTE         ArgData,
                         ULONG         ArgNumber,
                         ULONG         ArgRow,
                         PDC           pdcArg,
                         ULONG         FunN)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG              ulResult;        /* Return value               */
    DevRect            LocalBounds;     /* local bounds in Device     */

    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);

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

    /******************************************************************/
    /* If the number of pels to draw is zero leave the function       */
    /******************************************************************/
    if (ArgNumber == 0)
    {
        ExitDriver(pdcArg, FunN, EDF_STANDARD);
        return(OK);
    }

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


    /******************************************************************/
    /* 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 IMAGEDATA_ERR_EXIT;
        }
    }

    /******************************************************************/
    /* Check for an invalid count                                     */
    /******************************************************************/
    if (ArgNumber > MAX_IMAGE_LENGTH)
    {
        LogError(PMERR_INV_IMAGE_DATA_LENGTH);
        goto IMAGEDATA_ERR_EXIT;
    }

    /******************************************************************/
    /* Return an error if there is no currently selected bitmap       */
    /* and we will be actually drawing.                               */
    /******************************************************************/
    if ( (pdc->DCIBitmapType & BITMAP_NOT_SELECTED) &&
         FunNTest(COM_DRAW) )
    {
        LogError(PMERR_NO_BITMAP_SELECTED);
        goto IMAGEDATA_ERR_EXIT;
    }

    /******************************************************************/
    /* Obtain starting co-ord for data                                */
    /******************************************************************/
    AIxfer.ptsStart.x = pdc->DCICurrPosAI.X;
    AIxfer.ptsStart.y = pdc->DCICurrPosAI.Y + (USHORT)ArgRow;

    /******************************************************************/
    /* Set Result to OK for correlation                               */
    /******************************************************************/
    ulResult = OK;

    /******************************************************************/
    /* If we will need bounds for any reason then get them            */
    /******************************************************************/
    if ((FunNTest(COM_BOUND | COM_ALT_BOUND)             ) ||
        (cursor_data.cursor_status & CURSOR_SOFTWARE     ) ||
#ifdef DCAF                                                               //DCAF
        DCAFBoundsRequired(FunN) ||                                       //DCAF
#endif                                                                    //DCAF
        ((FunNTest(COM_CORRELATE) && (pdc->DCICorrNum))))
    {
        LocalBounds[0].X = AIxfer.ptsStart.x;
        LocalBounds[0].Y = AIxfer.ptsStart.y;
        LocalBounds[1].X = (USHORT)((ULONG)LocalBounds[0].X + ArgNumber - 1);
        LocalBounds[1].Y = LocalBounds[0].Y;

        if (FunNTest(COM_BOUND | COM_ALT_BOUND))
        {
            /**********************************************************/
            /* Bounds are required so accumulate them                 */
            /**********************************************************/
            eddg_AddBounds ((pDevRect)LocalBounds,
                             FunN,
                             COORD_AI);
        }

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

        if (FunNTest(COM_CORRELATE) && (pdc->DCICorrNum))
        {
            /**********************************************************/
            /* Correlation is required so do it                       */
            /**********************************************************/
            ulResult = eddg_CheckRectCorrelation((pDevRect)LocalBounds);
        }
    }

    /******************************************************************/
    /* If the COM_DRAW bit is off or the number of Clip rectangles    */
    /* is zero or the row is off the bottom of the bitmap then        */
    /* leave the function.                                            */
    /******************************************************************/
    if ( !(FunNTest(COM_DRAW))    ||
         pdc->DCIEngineClips == 0 ||
         AIxfer.ptsStart.y >= pdc->DCISelListEntry->Info.Height )
    {
        goto IMAGEDATA_OK_EXIT;
    }

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

    /******************************************************************/
    /* if the cursor is colour then disable it and maybe exclude it   */
    /******************************************************************/
    if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
    {
        eddm_ExcludeCursor(LocalBounds, COORD_AI);
    }

    /******************************************************************/
    /* In the image data, a '0' represents a pixel in the image       */
    /* background colour and a '1' a pixel in the image foreground    */
    /* colour. If we are drawing into a (1,1) bitmap then the         */
    /* interpretation of bits inside the bitmap is the same. We       */
    /* therefore set the foreground colour to 1 and background colour */
    /* to 0 to effectively copy the image data directly into the      */
    /* bitmap, under control of the mixes.                            */
    /******************************************************************/
#ifndef   _8514
    ShadowXGARegs.FgCol = (USHORT)pdc->DCIImagColatts.ForeColor;
    ShadowXGARegs.BgCol = (USHORT)pdc->DCIImagColatts.BackColor;

    /******************************************************************/
    /* Set up the hardware for the mixes.                             */
    /******************************************************************/
    ShadowXGARegs.FgMix = WinToXway[pdc->DCICurImgAts.ibnd.usMixMode];
    ShadowXGARegs.BgMix = WinToXway[pdc->DCICurImgAts.ibnd.usBackMixMode];
    ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
#else
    #ifndef   BPP24
    Shadow8514Regs.Color_1 = (USHORT)pdc->DCIImagColatts.ForeColor;
    Shadow8514Regs.Color_0 = (USHORT)pdc->DCIImagColatts.BackColor;
    #else
    Shadow8514Regs.Color_1 = pdc->DCIImagColatts.ForeColor;
    Shadow8514Regs.Color_0 = pdc->DCIImagColatts.BackColor;
    #endif

    /******************************************************************/
    /* Set up the hardware for the mixes.                             */
    /******************************************************************/
    Shadow8514Regs.Function_1.Mix = WinToXway[pdc->DCICurImgAts.ibnd.usMixMode];
    Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COL1;

    Shadow8514Regs.Function_0.Mix = WinToXway[pdc->DCICurImgAts.ibnd.usBackMixMode];
    Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COL0;
    Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
#endif

    /******************************************************************/
    /* Copy the shadow registers to the hardware if required.         */
    /******************************************************************/
    TransferShadowRegisters(TSR_COLOUR_MIX);

    /******************************************************************/
    /* Set up access to the clip rectangles                           */
    /******************************************************************/
    AIxfer.pClipRects = pdc->DCIClipRects;

#ifndef _8514

    if (!softDrawInUse)
    {
        /**************************************************************/
        /* Hardware will be used to draw.                             */
        /* The maximum data length is 2040 (the engine ensures this)  */
        /* so the data will always fit in the PHUNK.                  */
        /*                                                            */
        /* Remember the number passed to us is the number of bits,    */
        /* and there are 8 bits per byte.                             */
        /*                                                            */
        /* Wait for the h/w to complete before doing the copy, in     */
        /* case the phunk was already in use.                         */
        /**************************************************************/
        WaitForRealHW;

        memcpy(pPhunkVirt,
               ArgData,
               (ArgNumber+7)/8 );

        AIxfer.pPels = (PBYTE)pPhunkPhys;
    }
    else
    {
        /**************************************************************/
        /* Software drawing is active, so just transfer the           */
        /* virtual address of the image data into AIxfer.             */
        /**************************************************************/
        AIxfer.pPels = ArgData;
    }

#else // _8514

        /**************************************************************/
        /* Copying the data to the PHUNK is not necessary for the     */
        /* 8514.                                                      */
        /**************************************************************/
        AIxfer.pPels = ArgData;

#endif // _8514

    /******************************************************************/
    /* Pass the width of the image via the parameter block.           */
    /******************************************************************/
    AIxfer.ulCount = ArgNumber;

    /******************************************************************/
    /* There is no need to PHUNK the destination bitmap since if it   */
    /* is not the screen then we will be in software drawing mode     */
    /* anyway                                                         */
    /******************************************************************/
    AIxfer.pbmhDest = pdc->DCISelListEntry;

    /******************************************************************/
    /* Set up the bounds for the clip rectangles                      */
    /******************************************************************/
    if (pdc->DCIEngineClips > CACHED_CLIPS)
    {
        /**************************************************************/
        /* There are more clips than fit in the cache, so set         */
        /* the bounds which intersect clip to the image scanline.     */
        /**************************************************************/
        pdc->ClipChanged = TRUE;

        GetClipsBounds.X0 = AIxfer.ptsStart.x;
        GetClipsBounds.X1 = AIxfer.ptsStart.x + ArgNumber;
        GetClipsBounds.Y0 = pdc->DCIBoundingClip[1].Y - AIxfer.ptsStart.y;
        GetClipsBounds.Y1 = GetClipsBounds.Y0 + 1;
    }
    else if (pdc->ClipChanged )
    {
        /**************************************************************/
        /* Set the bounds which intersect clip to whole drawing area  */
        /**************************************************************/
        GetClipsBounds.X0 = pdc->DCIBoundingClip[0].X;
        GetClipsBounds.X1 = pdc->DCIBoundingClip[1].X + (USHORT)1;
        GetClipsBounds.Y0 = pdc->DCIBoundingClip[0].Y;
        GetClipsBounds.Y1 = pdc->DCIBoundingClip[1].Y + (USHORT)1;
    }

    eddb_DrawThroughClips((*pDrawFunctions)[index_PMIMAGEDATA],
                          (PUSHORT)&AIxfer.cClips);

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

IMAGEDATA_OK_EXIT:
    reenable_cursor();
    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(ulResult);

IMAGEDATA_ERR_EXIT:
    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(ERROR_ZERO);
}
