/*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          = EDDBSETP                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor Function:          */
/*                     SetPel                                         */
/*                                                                    */
/*   Function        = SetPel sets a given pel using the current      */
/*                     line foreground colour and mix.                */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_DDIMISC
#define INCL_GRE_CLIP
#ifdef DCAF                                                               //DCAF
#define INCL_GRE_BITMAPS                                                  //DCAF
#endif                                                                    //DCAF
#include <eddinclt.h>

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

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

#include <eddaextf.h>
#include <eddbextf.h>
#include <eddgextf.h>
#include <eddmextf.h>
#include <convfuns.h>

#ifdef DCAF                                                               //DCAF
#include <dcafextf.h>                                                     //DCAF
#endif                                                                    //DCAF

#include <eddhmacr.h>

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

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

#ifdef _8514
#include <8514.h>
#endif


extern BYTE                WinToXway[];

extern ULONG               PixelOp;
#ifndef   _8514
extern MMReg               ShadowXGARegs;
extern pMMReg              pXGARegs;
extern pMMReg              pRealXGARegs;
#else
extern MM8514Reg           Shadow8514Regs;
extern pMM8514Reg          p8514Regs;
#endif
extern SHORT               softDrawInUse;
extern VOID                eddf_MESS(VOID);

#ifdef _8514
extern VOID CopyMemoryToVRAM(PVOID,ULONG,ULONG,ULONG,ULONG);
extern VOID MemoryPelToVRAMPel(PVOID,ULONG,ULONG,ULONG,ULONG,ULONG);
extern VOID CopyVRAMToMemory(PVOID,ULONG,ULONG,ULONG,ULONG);
#endif

extern ONEPELBUFFER        get_and_set_pel_buffer;

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

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



/**********************************************************************/
/*                                                                    */
/*   SetPel sets a pel given in World co-ords using the current line  */
/* foreground colour and mix.  It does not affect the current         */
/* position.                                                          */
/*                                                                    */
/*   Note that a single pel can only lie within one clip region       */
/*                                                                    */
/**********************************************************************/
DDIENTRY eddb_SetPel (HDC        hdc,
                      PPOINTL    ArgPoint,
                      PDC        pdcArg,
                      ULONG      FunN)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG              Result;          /* Return value               */
    ULONG              i;
    DevRect            LocalBounds;     /* local bounds in Device     */
    POINTS             pel_coord;
#ifdef _8514
    #ifdef   BPP24
    ULONG              usPelValue;
    #else
    USHORT             usPelValue;
    #endif
#endif

    ULONG              temp;           /* Temp variable for swapp byte */

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

    /******************************************************************/
    /* 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_AREA) )
        {
            LogError(PMERR_INV_IN_AREA);
        }

        else /* COM_PATH */
        {
            LogError(PMERR_INV_IN_PATH);
        }
        goto SETPEL_ERR_EXIT;

    } /* path or area definition */

    /******************************************************************/
    /* Set the return value to OK                                     */
    /******************************************************************/
    Result = OK;

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


    /******************************************************************/
    /* Convert the point from World co-ords to A.I.                   */
    /******************************************************************/
    if ( OK != eddg_Convert ((PULONG)ArgPoint,
                             (PULONG)&pel_coord,
                             COORD_WORLD,
                             COORD_AI,
                             1,
                             COM_TRANSFORM) )
    {
        goto SETPEL_ERR_EXIT;
    }


    /******************************************************************/
    /* If bounds determination required then accumulate bounds        */
    /******************************************************************/
    if (FunNTest(COM_BOUND | COM_ALT_BOUND))
    {
        /**************************************************************/
        /* Initialise local bounds to the point                       */
        /**************************************************************/
        LocalBounds[0].X = LocalBounds[1].X = pel_coord.x;
        LocalBounds[0].Y = LocalBounds[1].Y = pel_coord.y;

        /**************************************************************/
        /* Update current bounds in DC instance data with local       */
        /* bounds                                                     */
        /**************************************************************/
        eddg_AddBounds ((pDevRect)LocalBounds,
                         FunN,
                         COORD_AI);

    }    /* end of bounds calculation                                 */


    /******************************************************************/
    /* If correlation requested then correlate                        */
    /******************************************************************/
    if (FunNTest(COM_CORRELATE) && (pdc->DCICorrNum))
    {
        /**************************************************************/
        /* Now correlate                                              */
        /**************************************************************/
        for (i = pdc->DCICorrNum; i--; )
        {
           if ((pdc->DCICorrRects[i][0].X <= pel_coord.x) &&
               (pdc->DCICorrRects[i][1].X >= pel_coord.x) &&
               (pdc->DCICorrRects[i][0].Y <= pel_coord.y) &&
               (pdc->DCICorrRects[i][1].Y >= pel_coord.y))
           {
               Result = OK_CORR;
               break;
           }
        }
    } /* correlation required */

    /******************************************************************/
    /* If the Draw Bit is not set then no drawing is required and we  */
    /* can leave now.                                                 */
    /******************************************************************/
    if ( !FunNTest(COM_DRAW) )
    {
        goto SETPEL_OK_EXIT;
    }

    /******************************************************************/
    /* Return an error if there is no currently selected bitmap       */
    /* Otherwise set ListEntry to the selected Bitmap list entry      */
    /******************************************************************/
    if (pdc->DCIBitmapType & BITMAP_NOT_SELECTED)
    {
        LogError(PMERR_NO_BITMAP_SELECTED);
        goto SETPEL_ERR_EXIT;
    }


    /******************************************************************/
    /* select the SetPel pixel op                                     */
    /******************************************************************/
    PixelOp = BACK_SRC_BACK_COL  |
              FORE_SRC_FORE_COL  |
              STEP_PXBLT         |
              SRC_PIX_MAP_A      |
              DST_PIX_MAP_B      |
              PAT_PIX_MAP_FORE   |
              MASK_PIX_MAP_OFF   |
              DRAW_MODE_DONTCARE |
              DIR_OCTANT_LRTB;

    /******************************************************************/
    /* transfer the pixel to the screen                               */
    /******************************************************************/
#ifdef _8514

   /* make sure the color is in the right format, defect #74624 */

    usPelValue =  pdc->DCILineColatts.ForeColor;

    if (!softDrawInUse)
    {
      if (pdc->DCISelListEntry->Info.BitCount == 16)
      {

         usPelValue = pdc->DCILineColatts.ForeColor;
         usPelValue = EnsureIntel16bpp(usPelValue);

      }

      else if (pdc->DCISelListEntry->Info.BitCount == 24)
      {
         temp = (pdc->DCILineColatts.ForeColor >> 16) & 0x000000FF;
         temp |= (pdc->DCILineColatts.ForeColor) & 0x0000FF00;
         temp |= (pdc->DCILineColatts.ForeColor << 16 ) & 0x00FF0000;
         usPelValue =  temp;
      }
    }

    get_and_set_pel_buffer.phys_addr = &usPelValue;
#endif

#ifdef DCAF                                                               //DCAF
    blt_one_pel( pel_coord,                                               //DCAF
                 WinToXway[pdc->DCICurLinAts.lbnd.usMixMode],             //DCAF
                 FunN );                                                  //DCAF
#else                                                                     //DCAF
    blt_one_pel(pel_coord,WinToXway[pdc->DCICurLinAts.lbnd.usMixMode]);
#endif                                                                    //DCAF

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

    return(Result);


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

    return(ERROR_ZERO);
}





/**********************************************************************/
/*     blt_one_pel returns FALSE if the pixel is clipped out          */
/**********************************************************************/


#ifdef DCAF                                                               //DCAF
SHORT blt_one_pel(POINTS  pel_coord,                                      //DCAF
                  USHORT  Mix,                                            //DCAF
                  ULONG   FunN)                                           //DCAF
#else                                                                     //DCAF
SHORT blt_one_pel(POINTS  pel_coord,
                  USHORT  Mix)
#endif                                                                    //DCAF
{

    DevRect   ExcludeRect;
#ifdef _8514
    ULONG     VRAMptr;
    BOOL      fSetPel;
    ULONG     F_Mix;    // 76949
#endif
#ifdef DCAF                                                               //DCAF
    RECTL               rclDCAF;                                          //DCAF
#endif                                                                    //DCAF

    /******************************************************************/
    /* Check if the pel intersects with the bounding clip of the area */
    /* we are drawing into. This required by the engine function which*/
    /* returns the clip rectangles.                                   */
    /******************************************************************/
    if (pel_coord.x < 0 || pel_coord.y < 0  ||
        pel_coord.x > pdc->DCISelListEntry->Info.HWWidth||
        pel_coord.y > pdc->DCISelListEntry->Info.HWHeight )
    {
        return(FALSE);
    }

    /******************************************************************/
    /* call the engine to get the clip rectangle which includes the   */
    /* pel to transfer: this is done by specifying a bounding         */
    /* rectangle comprising only the pel. If no clip rectangle        */
    /* returned the pel is clipped out (error)                        */
    /******************************************************************/
    GetClipsBounds.X0 = pel_coord.x;
    GetClipsBounds.X1 = GetClipsBounds.X0 + (USHORT)1;
    GetClipsBounds.Y0 = pdc->DCISelListEntry->Info.HWHeight -
                                                            pel_coord.y;
    GetClipsBounds.Y1 = GetClipsBounds.Y0 + (USHORT)1;

    GetClipsControl.ircStart = 1;
    GetClipsControl.crcReturned = 0;

    edda_GetClipRectangles();

    if ( !GetClipsControl.crcReturned )
    {
        return(FALSE);
    }

#ifdef DCAF                                                               //DCAF
    /******************************************************************/  //DCAF
    /* Accumulate DCAF screen bounds if required                      */  //DCAF
    /******************************************************************/  //DCAF
    if ( ((FunN & 0xFF) == (NGreSetPel & 0xFF)) &&                        //DCAF
         DCAFBoundsRequired(FunN) )                                       //DCAF
    {                                                                     //DCAF
        /**************************************************************/  //DCAF
        /* Set up an exclusive RECTL in screen coords.                */  //DCAF
        /**************************************************************/  //DCAF
        rclDCAF.xLeft = pel_coord.x;                                      //DCAF
        rclDCAF.xRight = rclDCAF.xLeft + 1;                               //DCAF
                                                                          //DCAF
        rclDCAF.yBottom = pdc->DCISelListEntry->Info.HWHeight -           //DCAF
                                                        pel_coord.y;      //DCAF
        rclDCAF.yTop = rclDCAF.yBottom + 1;                               //DCAF
                                                                          //DCAF
        /**************************************************************/  //DCAF
        /* Add the pel to the Screen Bounds.                          */  //DCAF
        /**************************************************************/  //DCAF
        AccumulateScreenBounds(&rclDCAF);                                 //DCAF
    }                                                                     //DCAF
#endif                                                                    //DCAF

    /******************************************************************/
    /* exclude the cursor and inhibit updates                         */
    /******************************************************************/
    if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
    {
        /**************************************************************/
        /* exclude rectangle is just the single pel we are affecting  */
        /**************************************************************/
        ExcludeRect[0].X = pel_coord.x;
        ExcludeRect[0].Y = pel_coord.y;
        ExcludeRect[1].X = pel_coord.x;
        ExcludeRect[1].Y = pel_coord.y;
        eddm_ExcludeCursor(ExcludeRect,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 pel mix                                                */
    /******************************************************************/
#ifndef   _8514
    ShadowXGARegs.FgMix = (BYTE)Mix;
    ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;

    /******************************************************************/
    /* Set the pel colour                                             */
    /******************************************************************/
    ShadowXGARegs.FgCol = (USHORT)pdc->DCILineColatts.ForeColor;


    /******************************************************************/
    /* now get the physical address of the bitmap.                    */
    /******************************************************************/

    /******************************************************************/
    /* set the bitmap dimensions and format                           */
    /******************************************************************/
    ShadowXGARegs.PixMapFormatB = (BYTE)pdc->DCISelListEntry->Info.HWFormat;
    ShadowXGARegs.PixMapWidthB  = pdc->DCISelListEntry->Info.HWWidth;
    ShadowXGARegs.PixMapHeightB = pdc->DCISelListEntry->Info.HWHeight;

    /******************************************************************/
    /* Set up address depending on which mode we're in                */
    /******************************************************************/
    if (softDrawInUse)
    {
        ShadowXGARegs.PixMapBaseB = (ULONG)pdc->DCISelListEntry->Bitmap;
    }
    else
    {
        ShadowXGARegs.PixMapBaseB = pdc->DCISelListEntry->BMPhys;
    }

    /******************************************************************/
    /* set map A as the single pixel buffer                           */
    /******************************************************************/
    ShadowXGARegs.PixMapFormatA = (BYTE)pdc->DCISelListEntry->Info.HWFormat;

    if (softDrawInUse)
    {
        ShadowXGARegs.PixMapBaseA = (LONG) get_and_set_pel_buffer.virt_addr;
    }
    else
    {
        ShadowXGARegs.PixMapBaseA = get_and_set_pel_buffer.phys_addr;
    }

    ShadowXGARegs.PixMapWidthA  = 0;
    ShadowXGARegs.PixMapHeightA = 0;

    /******************************************************************/
    /* if pixmap A is the source (SetPel) then the source coordinates */
    /* are 0,0 and destination are the pel_coord; if pixmap A is the  */
    /* target then the source and destination coordinates are the     */
    /* opposite way round                                             */
    /******************************************************************/
    if ( PixelOp & SRC_PIX_MAP_A )
    {
        ShadowXGARegs.SrcXAddr =
        ShadowXGARegs.SrcYAddr = 0;
        ShadowXGARegs.DstXAddr = pel_coord.x;
        ShadowXGARegs.DstYAddr = pel_coord.y;
    }

    else /* pix map A is target */
    {
        ShadowXGARegs.DstXAddr =
        ShadowXGARegs.DstYAddr = 0;
        ShadowXGARegs.SrcXAddr = pel_coord.x;
        ShadowXGARegs.SrcYAddr = pel_coord.y;
    }

    /******************************************************************/
    /* Now the blt dimensions                                         */
    /******************************************************************/
    ShadowXGARegs.OpDim1 = 0;
    ShadowXGARegs.OpDim2 = 0;


    /******************************************************************/
    /* And go for it..                                                */
    /******************************************************************/
    ShadowXGARegs.PixOp = PixelOp;

    TransferShadowRegisters( TSR_MAP_A |
                             TSR_MAP_B |
                             TSR_COLOUR_MIX |
                             TSR_COORDINATES |
                             TSR_PIXELOP );

    if (softDrawInUse)
    {
        eddf_MESS();
    }

#else
    /******************************************************************/
    /* Set the pel colour                                             */
    /******************************************************************/
    #ifndef   BPP24
    Shadow8514Regs.Color_1 = (USHORT)pdc->DCILineColatts.ForeColor;
    #else
    Shadow8514Regs.Color_1 = pdc->DCILineColatts.ForeColor;
    #endif

    /******************************************************************/
    /* Set the pel colour and mix.                                    */
    /******************************************************************/
    Shadow8514Regs.Function_1.Mix = (BYTE)Mix;
    Shadow8514Regs.Function_1.SrcSelect = (BYTE)FUNC_2OP_COL1;

    Shadow8514Regs.Function_0.Mix = (BYTE)Mix;
    Shadow8514Regs.Function_0.SrcSelect = (BYTE)FUNC_2OP_COL0;

    /******************************************************************/
    /* now get the physical address of the bitmap.                    */
    /******************************************************************/

    /******************************************************************/
    /* set the bitmap dimensions and format                           */
    /******************************************************************/
    Shadow8514Regs.PixMapFormatB = (BYTE)pdc->DCISelListEntry->Info.HWFormat;
    Shadow8514Regs.PixMapWidthB = pdc->DCISelListEntry->Info.HWWidth;
    Shadow8514Regs.PixMapHeightB = pdc->DCISelListEntry->Info.HWHeight;

    /******************************************************************/
    /* Set up address depending on which mode we're in                */
    /******************************************************************/
    if (softDrawInUse)
    {
        Shadow8514Regs.PixMapBaseB = (ULONG)pdc->DCISelListEntry->Bitmap;
    }
    else
    {
        Shadow8514Regs.PixMapBaseB = pdc->DCISelListEntry->BMPhys;
    }

    /******************************************************************/
    /* set map A as the single pixel buffer                           */
    /******************************************************************/
    Shadow8514Regs.PixMapFormatA = (BYTE)pdc->DCISelListEntry->Info.HWFormat;

    if (softDrawInUse)
    {
        Shadow8514Regs.PixMapBaseA = (LONG) get_and_set_pel_buffer.virt_addr;
    }
    else
    {
        Shadow8514Regs.PixMapBaseA = get_and_set_pel_buffer.phys_addr;
    }

    Shadow8514Regs.PixMapWidthA = 0;
    Shadow8514Regs.PixMapHeightA = 0;

    /******************************************************************/
    /* if pixmap A is the source (SetPel) then the source coordinates */
    /* are 0,0 and destination are the pel_coord; if pixmap A is the  */
    /* target then the source and destination coordinates are the     */
    /* opposite way round                                             */
    /******************************************************************/
    if ( PixelOp & SRC_PIX_MAP_A )
    {
        Shadow8514Regs.SrcXAddr =
        Shadow8514Regs.SrcYAddr = 0;
        Shadow8514Regs.DstXAddr = pel_coord.x;
        Shadow8514Regs.DstYAddr = pel_coord.y;
        fSetPel = TRUE;
    }

    else /* pix map A is target */
    {
        Shadow8514Regs.DstXAddr =
        Shadow8514Regs.DstYAddr = 0;
        Shadow8514Regs.SrcXAddr = pel_coord.x;
        Shadow8514Regs.SrcYAddr = pel_coord.y;
        fSetPel = FALSE;
    }

    VRAMptr = pel_coord.y + ( pel_coord.x << 16 );

    /******************************************************************/
    /* Now the blt dimensions                                         */
    /******************************************************************/
    Shadow8514Regs.OpDim1 = 0;
    Shadow8514Regs.OpDim2 = 0;


    /******************************************************************/
    /* And go for it..                                                */
    /******************************************************************/
    Shadow8514Regs.PixOp = PixelOp;

    TransferShadowRegisters( TSR_COLOUR_MIX );

    if (softDrawInUse)
    {
        eddf_MESS();
    }
    else
    {
        if (fSetPel)
        {
#ifndef _8514
           /* Original code before CMVC 76949   XGA only. */
            CopyMemoryToVRAM((PVOID)get_and_set_pel_buffer.phys_addr,    
                             VRAMptr, 0, 0, Shadow8514Regs.PixMapFormatA); 
#else
           /* New code for CMVC 76949    8514 or S3 */
           /* The 8514/S3 code requires the process of variable mix values in order to do */
           /* proper display of a single pixel. CopyMemoryToVRAM does not support this    */
           /* variable needs so we created a similar function called MemoryPelToVRAMPel   */
           /* for now, to take care of it. The name might change later... */

           /* Find proper foreground color source for the mix.  */
           F_Mix = Mix | ( Shadow8514Regs.Function_1.SrcSelect << 5);

           MemoryPelToVRAMPel((PVOID)get_and_set_pel_buffer.phys_addr,
                               VRAMptr,
                               F_Mix,                   /* Forground mix */
                               Mix,                     /* Background mix */
                               Shadow8514Regs.PixMapFormatA);
#endif


        }
        else
        {
            CopyVRAMToMemory((PVOID)get_and_set_pel_buffer.phys_addr,
                             VRAMptr, 0, 0, Shadow8514Regs.PixMapFormatA);
        }
    }

#endif


    /******************************************************************/
    /* reenable cursor updates                                        */
    /******************************************************************/
    reenable_cursor();

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

    return(TRUE);

} /* blt_one_pel */
