/*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          = EDDBGETP                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor Function:          */
/*                     GetPel                                         */
/*                                                                    */
/*   Function        = GetPel gets the colour index of a given pel    */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/*   73816 - Jim Reid                                                 */
/*           Add check so that memory DC bitmap coordinates are not   */
/*           converted to A.I. coordinates, but instead are           */
/*           transformed against the bitmap size.                     */
/*                                                                    */
/**********************************************************************/

#define INCL_DDICOMFLAGS
#define INCL_WINP_FSRS
#define INCL_DDIMISC
#define INCL_GRE_PALETTE

#include <eddinclt.h>

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

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

#include <eddbextf.h>
#include <eddcextf.h>
#include <eddgextf.h>
#include <eddmextf.h>

#include <eddhmacr.h>

#include <twozero.h>

#include <convfuns.h>

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


extern ULONG            PixelOp;
#ifndef   _8514
extern pMMReg           pRealXGARegs;
#endif
extern SHORT            softDrawInUse;
extern ONEPELBUFFER     get_and_set_pel_buffer;

extern RGB2             HWPalette[HW_PAL_SIZE];
extern PRGB2            MemoryDeviceDefaultPalette;
extern USHORT           SizeOfHWPalette;
extern DDTType          DDT;
extern BOOL             fRealizeSupported;




/**********************************************************************/
/*                                                                    */
/*   GetPel returns the colour index or RGB value for a pel given in  */
/* world co-ords.                                                     */
/*                                                                    */
/*   An error is returned if the pel lies outside the bitmap.         */
/* Clipping has no affect on this function.                           */
/*                                                                    */
/**********************************************************************/

DSPENTRY eddb_GetPel (HDC        hdc,
                      PPOINTL    ArgPoint,
                      PDC        pdcArg,
                      ULONG      FunN)

{
#define TFUNC "eddb_GetPel"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG       ulLogIndex;              /* returned to Engine        */
    POINTS      pel_coord;
    ULONG       ulPhyIndex;

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

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

    /******************************************************************/
    /* if INFO DC, return error                                       */
    /******************************************************************/
    if (pdc->DCIDCType == OD_INFO)
    {
        LOGERR(TFUNC, "Info DC", FNULL, 0, PMERR_PEL_NOT_AVAILABLE);
        goto GETPEL_ERR_EXIT;
    }

    /******************************************************************/
    /* Return an error if there is no currently selected bitmap       */
    /******************************************************************/
    if (pdc->DCIBitmapType & BITMAP_NOT_SELECTED)
    {
        LOGERR(TFUNC, "No selected Bitmap", FNULL, 0,
                                             PMERR_NO_BITMAP_SELECTED);
        goto GETPEL_ERR_EXIT;
    }


    if ( FunNTest(COM_TRANSFORM) )
    {
        /******************************************************************/
        /* 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 GETPEL_ERR_EXIT;
        }
    }
    else
    {                                                                          /*73816*/
        if ( pdc->DCIDCType == OD_MEMORY )                                     /*73816*/
        {                                                                      /*73816*/
            /**********************************************************/       /*73816*/
            /* Do not convert to A.I. co-ords if the DC is a memory   */       /*73816*/
            /* DC, just flip the coordinate system of the bitmap.     */       /*73816*/
            /**********************************************************/       /*73816*/
            pel_coord.x = ArgPoint->x;                                         /*73816*/
            pel_coord.y = pdc->DCISelListEntry->Info.Height - ArgPoint->y - 1; /*73816*/
        }                                                                      /*73816*/
        else                                                                   /*73816*/
        {                                                                      /*73816*/
            /**************************************************************/
            /* Convert the point from Screen co-ords to A.I. coords. (ie. */
            /* from 0,0 bottom left of screen to 0,0 top right of screen).*/
            /* This is just flipping the X coord.                         */
            /**************************************************************/
            pel_coord.x = ArgPoint->x;
            pel_coord.y = DDT.ScreenHeight - ArgPoint->y - 1;
        }                                                                      /*73816*/
    }

    /******************************************************************/
    /* Return an error if the pel lies outside the bitmap             */
    /******************************************************************/
    if (pel_coord.x < 0 ||
        pel_coord.y < 0 ||
        pel_coord.x >= pdc->DCISelListEntry->Info.Width ||
        pel_coord.y >= pdc->DCISelListEntry->Info.Height)
    {
        LOGERR(TFUNC, "Pel outside bitmap", FNULL, 0,
                                         PMERR_PEL_NOT_AVAILABLE);
        goto GETPEL_ERR_EXIT;
    }

    /******************************************************************/
    /* select the GetPel pixel op                                     */
    /******************************************************************/
    PixelOp = BACK_SRC_SRC_PIX_MAP |
              FORE_SRC_SRC_PIX_MAP |
              STEP_PXBLT |
              SRC_PIX_MAP_B |
              DST_PIX_MAP_A |
              PAT_PIX_MAP_FORE |
              MASK_PIX_MAP_OFF |
              DRAW_MODE_DONTCARE |
              DIR_OCTANT_LRTB;

    /******************************************************************/
    /* transfer the pixel from the screen                             */
    /* blt_one_pel returns FALSE if the pixel is clipped out          */
    /* (cursor exclusion is handled by blt_one_pel)                   */
    /******************************************************************/
#ifdef _8514
    get_and_set_pel_buffer.phys_addr = &ulPhyIndex;
#endif

#ifdef DCAF                                                               //DCAF
    #ifndef _8514
    if ( !blt_one_pel(pel_coord, HWMIX_SOURCE, FunN) )                    //DCAF
    #else
    if ( !blt_one_pel(pel_coord, FUNC_S, FunN) )
    #endif
#else                                                                     //DCAF
    #ifndef _8514
    if ( !blt_one_pel(pel_coord, HWMIX_SOURCE) )
    #else
    if ( !blt_one_pel(pel_coord, FUNC_S) )
    #endif
#endif                                                                    //DCAF
    {
        LOGERR(TFUNC, "Pel clipped out", FNULL, 0,
                                          PMERR_PEL_IS_CLIPPED);
        goto GETPEL_ERR_EXIT;
    }


    /******************************************************************/
    /* blt_one_pel has copied the pel into our buffer.                */
    /* The buffer is arranged in motorola format, with the            */
    /* significant bits at the start of the buffer.                   */
    /******************************************************************/

    /******************************************************************/
    /* If we are in hardDraw mode then we must wait for the hardware  */
    /* to complete the blt from the screen into our single pel buffer.*/
    /******************************************************************/
    if (!softDrawInUse)
    {
        WaitForRealHW;
    }

    #ifdef _8514
    // Use virtual address if not going to hardware - MRC 65082
    if (softDrawInUse)
    #endif
    {
       ulPhyIndex = *get_and_set_pel_buffer.virt_addr;
    }

    #ifdef BPP24
    if (pdc->DCISelListEntry->Info.BitCount == 24)
    {
        /**************************************************************/
        /* Ensure that we have the 24bpp value in RGB format.         */
        /**************************************************************/
        if (DDT.fScreenFlags & USE_ATTDAC)
        {
            ulPhyIndex &= 0x00FFFFFF;
        }
        else
        {
           ulLogIndex = (ulPhyIndex >> 16) & 0x000000FF;
           ulLogIndex |= (ulPhyIndex) & 0x0000FF00;
           ulLogIndex |= (ulPhyIndex << 16 ) & 0x00FF0000;
           ulPhyIndex = ulLogIndex;
        }
    }
    else if (pdc->DCISelListEntry->Info.BitCount == 16)
    #else
    if (pdc->DCISelListEntry->Info.BitCount == 16)
    #endif
    {
        /**************************************************************/
        /* Ensure that we have the 16bpp value in Intel format.       */
        /**************************************************************/
        ulPhyIndex = EnsureIntel16bpp(ulPhyIndex);
    }
    else if (pdc->DCISelListEntry->Info.BitCount == 8)
    {
        /**************************************************************/
        /* When a BYTE is all we picked up then Motorola ordering     */
        /* does not worry us - just mask so we keep just 8 bits       */
        /**************************************************************/
        ulPhyIndex &= 0x000000FF;
    }
    else if (pdc->DCISelListEntry->Info.BitCount == 4)
    {
        /**************************************************************/
        /* The bits of the first pel in the BYTE are in the most      */
        /* significant bits.                                          */
        /**************************************************************/
        ulPhyIndex = (ulPhyIndex >> 4) & 0x0000000F;
    }
    else /* if (pdc->DCISelListEntry->Info.BitCount == 1) */
    {
        /**************************************************************/
        /* The bits of the first pel in the BYTE are in the most      */
        /* significant bits.                                          */
        /**************************************************************/
        ulPhyIndex = (ulPhyIndex >> 7) & 0x00000001;
    }

    if (pdc->DCIColFormat == LCOLF_RGB)
    {
        /**************************************************************/
        /* At 1bpp the possible RGB values are black and white        */
        /**************************************************************/
        if (pdc->DCISelListEntry->Info.BitCount == 1)
        {
            if (ulPhyIndex == 0)
            {
                ulLogIndex = 0x00000000;
            }
            else
            {
                ulLogIndex = 0x00ffffff;
            }
        }
        else if (pdc->DCISelListEntry->Info.BitCount == 16)
        {
            /**********************************************************/
            /* At 16 bpp we expand the 16bpp RGB value into a full    */
            /* RGB value in a ULONG                                   */
            /**********************************************************/
            ulLogIndex = (((ULONG)ulPhyIndex << 8) & 0x00F80000) |
                         (((ULONG)ulPhyIndex << 5) & 0x0000FC00) |
                         (((ULONG)ulPhyIndex << 3) & 0x000000F8);
        }
        #ifdef BPP24
        else if (pdc->DCISelListEntry->Info.BitCount == 24)
        {
            /**************************************************************/
            /* return the 24bpp value in Intel format.                    */
            /**************************************************************/
            ulLogIndex = ulPhyIndex;
        }
        #endif
        /**************************************************************/
        /* We are currently in RGB mode and therefore have to return  */
        /* an RGB value. If the current LCT is realizable and can     */
        /* produce the physical index then use the RGB value in the   */
        /* LCT, otherwise use the RGB value in the default physical   */
        /* palette.                                                   */
        /**************************************************************/
        else if (fRealizeSupported &&
                 (pdc->DCIColStatus & LCOL_REALIZABLE) &&
                 (ulPhyIndex >= pdc->DCILowIndex) &&
                 (ulPhyIndex <= pdc->DCIHighIndex) &&
                 (pdc->DCIColorTable[ulPhyIndex].PhyIndex !=
                                                        CLR_NOPHYINDEX))
        {
            /**********************************************************/
            /* Color table is realizable and entry is valid so use    */
            /* the RGB value.                                         */
            /**********************************************************/
            ulLogIndex = URGB(pdc->DCIColorTable[ulPhyIndex].LogRGB);
        }
        else
        {
            /**********************************************************/
            /* If we are a memory DC then use the RGB value from the  */
            /* device default physical palette. If we are a direct    */
            /* (screen) DC then use the RGB value in the HW palette.  */
            /**********************************************************/
            if (pdc->DCIDCType == OD_DIRECT)
            {
                ulLogIndex = (((PULONG)HWPalette)[ulPhyIndex] & RGB_MASK);
            }
            else
            {
                ulLogIndex = (MemoryDeviceDefaultULONG(ulPhyIndex) & RGB_MASK);
            }
        }
    }
    else /* index LCT or palette format */
    {
        /**************************************************************/
        /* Mode is index in LCT or palette so we need to convert our  */
        /* physical index back into a logical index.                  */
        /**************************************************************/
        ulLogIndex = PhyToLogIndex(ulPhyIndex);
    }

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

    PROFILE_EXIT(12);
    return(ulLogIndex);


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

    PROFILE_EXIT(12);

    return(ERROR_NEG);
}
#undef TFUNC
