/*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          = EDDCSUBR                                       */
/*                                                                    */
/*   Description     = Display Device Driver color subroutines        */
/*                                                                    */
/*   Function        =                                                */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/* Revisions:                                                         */
/*                                                                    */
/* 74638  10/13/93 Change Team  Check to see if palette entry is      */
/*                              explicit, and if so use the physical  */
/*                              index rather than translating.        */
/*                                                                    */
/**********************************************************************/
#define INCL_WINSYS
#define INCL_DDIMISC
#include <eddinclt.h>

#include <eddccone.h>
#include <edddtypt.h>

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

#include "eddhcone.h"   /* required by eddhtype.h */
#include "eddhtype.h"   /* required by convfuns.h */

#include "convfuns.h"

extern RGB2             HWPalette[HW_PAL_SIZE];
extern RGB2             RealizedLCTPalette[HW_PAL_SIZE];
extern RGB2             FullSizeDeviceDefaultPalette[256];
extern RGB2             Reduced64DeviceDefaultPalette[64];
extern RGB2             Reduced16DeviceDefaultPalette[16];
extern PRGB2            DirectDeviceDefaultPalette;
extern PRGB2            MemoryDeviceDefaultPalette;
extern ULONG            ulDirectDeviceDefaultPaletteSize;

extern PCOLORTABLE      DefaultDirectLogicalColorTable;
extern PCOLORTABLE      DefaultMemoryLogicalColorTable;
extern COLORTABLETYPE   DefaultFourBppTable[DFLT_LOG_COL_TABLE_SIZE];
extern COLORTABLETYPE   DefaultEightBppTable16[DFLT_LOG_COL_TABLE_SIZE];
extern COLORTABLETYPE   DefaultEightBppTable32[DFLT_LOG_COL_TABLE_SIZE];
extern COLORTABLETYPE   DefaultEightBppTable64[DFLT_LOG_COL_TABLE_SIZE];
extern COLORTABLETYPE   DefaultEightBppTable128[DFLT_LOG_COL_TABLE_SIZE];
extern COLORTABLETYPE   DefaultEightBppTable256[DFLT_LOG_COL_TABLE_SIZE];
extern COLORTABLETYPE   DefaultSixteenBppTable[DFLT_LOG_COL_TABLE_SIZE];

extern COLORTABLETYPE   DirectSpecialColorTable[];
extern COLORTABLETYPE   MemorySpecialColorTable[];

extern BYTE             PaletteFudgeTable256[256];
extern BYTE             PaletteFudgeTable128[128];
extern BYTE             PaletteFudgeTable64[64];
extern BYTE             PaletteFudgeTable32[32];
extern BYTE             PaletteFudgeTable16[16];

extern ULONG            cPhysicalColors;
extern USHORT           SizeOfHWPalette;
extern USHORT           MaxLogColorIndex;

extern DDTType          DDT;

extern BOOL             fRealizeSupported;
extern HDC              ColorTableRealized;
extern ULONG            RealizedWhiteIndex;
extern ULONG            RealizedBlackIndex;
extern ULONG            ulLastSearched;
extern ULONG            ulIndexLastSearched;

/**********************************************************************/
/*                                                                    */
/*   InitDefaultColorTables initialises the HWPalette structure,and   */
/*   sets up various global constants such as the size of the Palette */
/*   which depend on the device bpp.                                  */
/*                                                                    */
/*   It initialises the real h/w from the HWPalette structure.        */
/*                                                                    */
/*   The routine is called by FillPhysicalDeviceBlock which requests  */
/* and releases the enter driver semaphore around it.                 */
/*                                                                    */
/**********************************************************************/
VOID InitDefaultColorTables (VOID)
{
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    ULONG     i;           /* general loop variable                   */
    ULONG     SpecialIndex;

    /******************************************************************/
    /* First clear all the entries in the HWPalette.                  */
    /* This is statically allocated to be big enough for 256 entries  */
    /* (as required for 8bpp).                                        */
    /******************************************************************/
    memset (HWPalette, 0, sizeof(HWPalette));

    /******************************************************************/
    /* Set up the palette and logical color table for the appropriate */
    /* bpp.                                                           */
    /* Also set up any global constants for this format.              */
    /******************************************************************/
    if (DDT.BitCount == 8)
    {
        /**************************************************************/
        /* Eight bits per pel                                         */
        /**************************************************************/
        DefaultDirectLogicalColorTable = DefaultEightBppTable256;
        DefaultMemoryLogicalColorTable = DefaultEightBppTable256;

        cPhysicalColors  = 256;
        SizeOfHWPalette  = 256;
        MaxLogColorIndex = 255;

        fRealizeSupported = TRUE;

        /**************************************************************/
        /* Now set the entries in the SpecialColorTables.             */
        /**************************************************************/
        DirectSpecialColorTable[-CLR_TRUE ].PhyIndex = 0xFF;
        DirectSpecialColorTable[-CLR_WHITE].PhyIndex = 0xFF;
        MemorySpecialColorTable[-CLR_TRUE ].PhyIndex = 0xFF;
        MemorySpecialColorTable[-CLR_WHITE].PhyIndex = 0xFF;

        /**************************************************************/
        /* Now set up the initial device default palette in the       */
        /* HWPalette. This is the 256 entry device default palette.   */
        /**************************************************************/
        for (i=0; i<256; i++)
        {
            HWPalette[i] = FullSizeDeviceDefaultPalette[i];
        }
        DirectDeviceDefaultPalette = FullSizeDeviceDefaultPalette;
        MemoryDeviceDefaultPalette = FullSizeDeviceDefaultPalette;
        ulDirectDeviceDefaultPaletteSize = 256;
    }

    else if (DDT.BitCount == 4)
    {
        /**************************************************************/
        /* Four bits per pel                                          */
        /**************************************************************/
        DefaultDirectLogicalColorTable = DefaultFourBppTable;
        DefaultMemoryLogicalColorTable = DefaultFourBppTable;

        cPhysicalColors  = 16;
        SizeOfHWPalette  = 16;
        MaxLogColorIndex = 255;

        fRealizeSupported = TRUE;

        /**************************************************************/
        /* Now set the entries in the SpecialColorTable.              */
        /**************************************************************/
        DirectSpecialColorTable[-CLR_TRUE ].PhyIndex = 0x0F;
        DirectSpecialColorTable[-CLR_WHITE].PhyIndex = 0x0F;
        MemorySpecialColorTable[-CLR_TRUE ].PhyIndex = 0x0F;
        MemorySpecialColorTable[-CLR_WHITE].PhyIndex = 0x0F;

        /**************************************************************/
        /* Now set up the device default palette in the HWPalette.    */
        /* This is the 16 entry device default palette.               */
        /**************************************************************/
        for (i=0; i < 16; i++)
        {
            HWPalette[i] = Reduced16DeviceDefaultPalette[i];
        }
        DirectDeviceDefaultPalette = Reduced16DeviceDefaultPalette;
        MemoryDeviceDefaultPalette = Reduced16DeviceDefaultPalette;
        ulDirectDeviceDefaultPaletteSize = 16;
    }
    else /* if( (DDT.BitCount == 16)  || ( DDT.BitCount == 24 ) ) */
    {

        /**************************************************************/
        /* Sixteen bits per pel.                                      */
        /**************************************************************/
        DefaultDirectLogicalColorTable = DefaultSixteenBppTable;
        DefaultMemoryLogicalColorTable = DefaultSixteenBppTable;

        if ( DDT.BitCount == 16 ) {
           cPhysicalColors  = 65536;
        }
        else
        {
           cPhysicalColors  = 16777216;
        }

        MaxLogColorIndex = 255;        /* unchanged from 8bpp */

        fRealizeSupported = FALSE;

        /**************************************************************/
        /* Assume we want the XGA 16bpp value.                        */
        /**************************************************************/
        SpecialIndex = 0xFFFF;

        /**************************************************************/
        /* Now set the entries in the SpecialColorTable.              */
        /**************************************************************/
        DirectSpecialColorTable[-CLR_TRUE ].PhyIndex =
        DirectSpecialColorTable[-CLR_WHITE].PhyIndex =
        MemorySpecialColorTable[-CLR_TRUE ].PhyIndex =
        MemorySpecialColorTable[-CLR_WHITE].PhyIndex = SpecialIndex;

        /**************************************************************/
        /* 16bpp does not use a palette in our sense of the word, so  */
        /* we dont set anything into HWPalette.                       */
        /**************************************************************/
    }

    /******************************************************************/
    /* Now we write to the palette registers.                         */
    /* 16bpp XGA needs special palette handling - MATROX does not     */
    /* have a palette at all.                                         */
    /******************************************************************/
    #ifdef   BPP24
    if ((DDT.BitCount != 16) && (DDT.BitCount != 24 ))
    #else
    if (DDT.BitCount != 16)
    #endif
    {
        /**************************************************************/
        /* Copy the palette to the hardware.                          */
        /* This call will automatically take care of any color to     */
        /* mono mapping required                                      */
        /**************************************************************/
        #ifndef   _8514
        LoadPaletteEntries(0,
                           SizeOfHWPalette,
                           HWPalette);
        #else
        Load8514PaletteEntries(0,
                               SizeOfHWPalette,
                               HWPalette);
        #endif
    }
    else
    {
        /**************************************************************/
        /* We write values to the XGA palette registers to ensure     */
        /* correct operation at 16bpp, but this is not a palette as   */
        /* far as the driver is concerned.                            */
        /**************************************************************/
        #ifndef _8514
        LoadDirectPalette();
        #else
        #ifndef   CNT481
        // bvh will load the palette for us so this is a devoid function
        Load8514DirectPalette();
        #endif
        #endif
    }
}


/**********************************************************************/
/* LogToPhyIndex is a color utility routine that, given a logical     */
/* index, will return the correct physical index to use taking into   */
/* account the current mode (index, RGB or palette), the current      */
/* Logical Color Table, the current System Color Table, and the       */
/* current device default palette.                                    */
/**********************************************************************/
ULONG LogToPhyIndex(LONG LogIndex)
{
    /******************************************************************/
    /* Local variables.                                               */
    /******************************************************************/
    ULONG       PhyIndex;
    RGB2        ReqRGB;
    ULONG       fTrueFalse;

    /******************************************************************/
    /* This local flag must be FALSE for the default behaviour.       */
    /******************************************************************/
    fTrueFalse = FALSE;

    /******************************************************************/
    /* Check for a system (negative) index                            */
    /******************************************************************/
    if ( LogIndex < 0 )
    {
        /**************************************************************/
        /* Index is negative - either a special colour or a system    */
        /* colour                                                     */
        /**************************************************************/
        /**************************************************************/
        /* TRUE and FALSE must not be searched for in the palette     */
        /**************************************************************/
        if ( LogIndex == CLR_TRUE ||
             LogIndex == CLR_FALSE)
        {
            fTrueFalse = TRUE;
        }

        /**************************************************************/
        /* Negate LogIndex to get a positive index we can look it up  */
        /* in the table                                               */
        /**************************************************************/
        if ( (-LogIndex) < SPECIAL_COL_TAB_SIZE)
        {
            if (pdc->DCIDCType == OD_DIRECT)
            {
                PhyIndex = DirectSpecialColorTable[-LogIndex].PhyIndex;
                ReqRGB   = DirectSpecialColorTable[-LogIndex].LogRGB;
            }
            else
            {
#pragma message( __FILE__"(286) : Warning: not sure if this is right!")
/**********************************************************************/
/* I do not think we should use the special color table phyindex if   */
/* the memory DC is not using the default physical palette. But this  */
/* is the equivalent of the old code...                               */
/**********************************************************************/
                PhyIndex = MemorySpecialColorTable[-LogIndex].PhyIndex;
                ReqRGB   = MemorySpecialColorTable[-LogIndex].LogRGB;
            }
        }
        else
        {
            /**********************************************************/
            /* Invalid negative index                                 */
            /**********************************************************/
            PhyIndex = CLR_NOPHYINDEX;
        }
    }
    else
    {
        /**************************************************************/
        /* Value was positive - a 'normal' logical colour.            */
        /**************************************************************/
        /**************************************************************/
        /* Find out what the current mode is.                         */
        /**************************************************************/
        if (pdc->DCIColFormat == LCOLF_PALETTE)
        {
            /**********************************************************/
            /* we have a palette                                      */
            /**********************************************************/
            if (LogIndex < (LONG)pdc->Palette->usCountStored)
            {
                /******************************************************/
                /* This entry is valid so pick up the RGB from the    */
                /* palette.                                           */
                /******************************************************/
                ReqRGB   = pdc->Palette->entries[LogIndex].rgb;

                /******************************************************/
                /* The physical index depends if we are drawing to    */
                /* the screen or to a bitmap.                         */
                /******************************************************/
                if (pdc->DCIDCType == OD_DIRECT)
                {
                    /**************************************************/
                    /* Drawing to the screen means we use the value   */
                    /* of the slot assigned by RealizePalette.        */
                    /**************************************************/

                    /*
                    ** @74638 added the following three lines to check
                    ** for an explicit palette entry.
                    */

                    if (pdc->Palette->entries[LogIndex].rgb.fcOptions & PC_EXPLICIT)
                      PhyIndex = LogIndex;
                    else
                      PhyIndex = pdc->Palette->entries[LogIndex].bCurrent;
                }
                else
                {
                    /**************************************************/
                    /* Drawing to the bitmap means we use the logical */
                    /* palette index as our required index            */
                    /**************************************************/
                    PhyIndex = LogIndex;
                }
            }
            else
            {
                /******************************************************/
                /* The required index is outside the palette range    */
                /******************************************************/
                PhyIndex = CLR_NOPHYINDEX;
            }
        }
        else if (pdc->DCIColFormat != LCOLF_RGB)
        {
            /**********************************************************/
            /* Mode is index.                                         */
            /* Get the physical index directly from the LCT.          */
            /**********************************************************/

            /**********************************************************/
            /* Index is positive                                      */
            /**********************************************************/
            if (LogIndex <= (LONG)pdc->DCIHighIndex)
            {
                ReqRGB   = pdc->DCIColorTable[LogIndex].LogRGB;
                PhyIndex = pdc->DCIColorTable[LogIndex].PhyIndex;
            }
            else
            {
                #ifdef BPP24
                // @DMS some apps are sending in rgbs in this mode when 24bpp
                // so I am simulating RGB mode when index is greater than DCIHigh
                if (DDT.BitCount == 24)
                {
                   ReqRGB.bBlue  = ((PBYTE)&LogIndex)[0];
                   ReqRGB.bGreen = ((PBYTE)&LogIndex)[1];
                   ReqRGB.bRed   = ((PBYTE)&LogIndex)[2];
                   PhyIndex = MODE_WAS_RGB;
                   LogError(PMERR_INV_COLOR_ATTR);
                }
                else
                {
                   PhyIndex = CLR_NOPHYINDEX;
                }
                #else
                PhyIndex = CLR_NOPHYINDEX;
                #endif
            }
        }
        else
        {
            /**********************************************************/
            /* Mode is RGB so get it directly from the LogIndex.      */
            /* We dont actually convert it to a physical index here   */
            /* because there are various ways to do this dependant    */
            /* on circumstances, so its done below.  We must flag     */
            /* that we we in RGB mode incase we fall through all the  */
            /* special cases, so that we ensure we call the default   */
            /* routine to convert from RGB to physical index.         */
            /**********************************************************/
            if (((PBYTE)&LogIndex)[3]==0)
            {
                ReqRGB.bBlue  = ((PBYTE)&LogIndex)[0];
                ReqRGB.bGreen = ((PBYTE)&LogIndex)[1];
                ReqRGB.bRed   = ((PBYTE)&LogIndex)[2];
                PhyIndex = MODE_WAS_RGB;
            }
            else
            {
                /******************************************************/
                /* If the options bits are not zero then we return    */
                /* error.                                             */
                /******************************************************/
                PhyIndex = CLR_NOPHYINDEX;
            }
        }
    }

    /******************************************************************/
    /* At this point we have the RGB value and possibly the physical  */
    /* index as well.                                                 */
    /* Dependant on the bits per pel we massage this information in   */
    /* different ways.                                                */
    /******************************************************************/
    if (PhyIndex == CLR_NOPHYINDEX)
    {
        /**************************************************************/
        /* Invalid value no no need for further calculation           */
        /**************************************************************/
    }
    else if (pdc->DCISelListEntry->Info.BitCount == 1)
    {
        /**************************************************************/
        /* Target bitmap is 1 bpp so we must only return black or     */
        /* white.                                                     */
        /**************************************************************/
        PhyIndex = MapRGBToMono(&ReqRGB);
    }
    else if (DDT.BitCount == 16)
    {
        /**************************************************************/
        /* Map the RGB2 value into an RGB16 value. (16bpp pel value)  */
        /**************************************************************/
        PhyIndex = RGB16FromPRGB2(&ReqRGB);
    }
    #ifdef   BPP24
    else if (DDT.BitCount == 24)
    {
        /**************************************************************/
        /* Map the RGB2 value into an RGB24 value. (24bpp pel value)  */
        /**************************************************************/
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
          PhyIndex = RGB24FromPRGB2(&ReqRGB);
        }
        else
        {
          PhyIndex = RGB24FromPRGB2ATT(&ReqRGB);
        }
    }
    #endif
    else if (fRealizeSupported && !fTrueFalse)
    {
        /**************************************************************/
        /* If we support realization we must take some care here.     */
        /* True and False are not affected by realization so we       */
        /* already have the correct values for them.                  */
        /**************************************************************/
        if (ColorTableRealized)
        {
            /**********************************************************/
            /* There is currently a realized color table so we must   */
            /* search the palette for the required color.             */
            /* The search is necessary because it may not be us that  */
            /* is the current realized color table.                   */
            /**********************************************************/
              PhyIndex = SearchRealizedLCTPalette(ReqRGB);
        }
        else if (pdc->DCIColStatus & LCOL_REALIZABLE)
        {
#pragma message( __FILE__"(449) : Warning: not sure if this is right!")
/**********************************************************************/
/* If no color table is realized then we must surely have black and   */
/* white in the HW palette so why don't we use them here...           */
/**********************************************************************/
            /**********************************************************/
            /* CLR_BLACK and CLR_WHITE need special care here.        */
            /* In all other cases we already have the correct         */
            /* PhyIndex (being the index into the default table       */
            /* picked up from SysColorTable[..].PhyIndex              */
            /**********************************************************/
            if (LogIndex == CLR_BLACK)
            {
                PhyIndex = pdc->DCIColorTable[CLR_NEUTRAL].PhyIndex;
            }
            else if (LogIndex == CLR_WHITE)
            {
                PhyIndex = pdc->DCIColorTable[CLR_BACKGROUND].PhyIndex;
            }
        }
    }

    /******************************************************************/
    /* At this stage we have done almost all our massaging to get the */
    /* correct index.                                                 */
    /* However the one remaining twist is if we were in RGB mode and  */
    /* have not already found the physical index then we must call    */
    /* off to find this.                                              */
    /******************************************************************/
    if (PhyIndex == MODE_WAS_RGB)
    {
        PhyIndex = NearestDefaultPhysicalIndex(ReqRGB);
    }

    return(PhyIndex);
} /* LogToPhyIndex */


/**********************************************************************/
/* NearestDefaultPaletteIndex256()                                    */
/* -------------------------------                                    */
/*  takes an RGB2 value and returns the index of the nearest colour   */
/*  in the default 256 palette.                                       */
/*                                                                    */
/*                                                                    */
/* The default 256 entry palette consists of two parts:               */
/*                                                                    */
/*           Greys in slots 112 to 143.                               */
/*           Colours in slots 0 to 111, 144 to 255                    */
/*                                                                    */
/* The Colours are made up from:                                      */
/*          7 possible R values evenly spaced from 0 -> 255           */
/*          8 possible G values evenly spaced from 0 -> 255           */
/*          4 possible B values evenly spaced from 0 -> 255           */
/*                                                                    */
/* The Greys have 34 equal R,G + B values evenly spread from 0 -> 255 */
/*      (if you include the 'Colours' BLACK and WHITE)                */
/*                                                                    */
/* The Maths Involved                                                 */
/* ------------------                                                 */
/*                                                                    */
/* With N values spread from 0 to 255, the nearest value to X can be  */
/* calculated by:                                                     */
/*                                                                    */
/*      Distance between values :  Dist = 256 / (N - 1)               */
/*                                                                    */
/*      Index of Nearest Value :   Num  = (X + Dist / 2) / Dist       */
/*                                                                    */
/*      => Num = (X + (128 / (N - 1))) / (256 / (N - 1))              */
/*                                                                    */
/*      => Num = (X * (N-1) + 128) / 256                              */
/*                                                                    */
/* The first step in deciding on the nearest palette entry is to      */
/* decide if we have a Grey or a Colour. This is detailed later.      */
/*                                                                    */
/* If we have a Colour                                                */
/* -------------------                                                */
/*                                                                    */
/* As all colours are made up from a fixed set of R G and B values    */
/* the nearest colour can be found by first finding the nearest       */
/* R, G and B values individually.                                    */
/*                                                                    */
/* The Nearest R G and B values are:                                  */
/*                                                                    */
/*      RNum = (R * 6 + 128) / 256                                    */
/*      GNum = (G * 7 + 128) / 256                                    */
/*      BNum = (B * 3 + 128) / 256                                    */
/*                                                                    */
/* If you ignore the middle grey slots, the slot number corresponding */
/* to these values is given by:                                       */
/*                                                                    */
/*      Slot = RNum * 32 + GNum * 4 + BNum                            */
/*                                                                    */
/*  This can then be adjusted to allow for the Grey slots:            */
/*                                                                    */
/*      if (Slot > 111) Slot += 32                                    */
/*                                                                    */
/* If we have a Grey                                                  */
/* -----------------                                                  */
/*                                                                    */
/* The grey index is given by:                                        */
/*                                                                    */
/* ie   Grey = (G * 33 + 128) / 256                                   */
/*                                                                    */
/* the slot this maps to is given by                                  */
/*                                                                    */
/*      if (Grey == 0)                                                */
/*          Slot = 0;       -- ie BLACK                               */
/*      else if (Grey == 33)                                          */
/*          Slot = 255;     -- ie WHITE                               */
/*      else                                                          */
/*          Slot = 111 + Grey                                         */
/*                                                                    */
/* Deciding if we have a Grey or Colour                               */
/* ------------------------------------                               */
/* We have a Grey if the Grey index corresponding to the R, G and B   */
/* values are the same:                                               */
/*      RGrey = (R * 33 + 128) / 256                                  */
/*      GGrey = (G * 33 + 128) / 256                                  */
/*      BGrey = (B * 33 + 128) / 256                                  */
/*                                                                    */
/* if (RGrey == GGrey == BGrey)                                       */
/*      Grey Value                                                    */
/* else                                                               */
/*      Colour Value                                                  */
/*                                                                    */
/* This eventually gives us....                                       */
/**********************************************************************/
ULONG NearestDefaultPaletteIndex256(RGB2* RGBColour)
{
    ULONG   Temp;
    ULONG   Red   = (*(ULONG*)RGBColour & RED_MASK)   >> 16;
    ULONG   Green = (*(ULONG*)RGBColour & GREEN_MASK) >>  8;
    ULONG   Blue  = (*(ULONG*)RGBColour & BLUE_MASK);


    /******************************************************************/
    /* Do we have a grey value or a colour                            */
    /******************************************************************/
    Temp = ( Red * 33 + 128 ) / 256;
    if ( (Temp == ( Green * 33 + 128 ) / 256 ) &&
         (Temp == ( Blue  * 33 + 128 ) / 256 ) )
    {
        /**************************************************************/
        /* We have a Grey value                                       */
        /**************************************************************/
        if (Temp == 0)
        {
            return(PaletteFudgeTable256[0]);            /* BLACK */
        }
        else if (Temp == 33)
        {
            return(PaletteFudgeTable256[255]);          /* WHITE */
        }
        else
        {
            return(PaletteFudgeTable256[111 + Temp]);
        }
    }
    else
    {
        /**************************************************************/
        /* We have a Colour value                                     */
        /**************************************************************/
        Temp =  ((Red   * 6 + 128) / 256) * 32 +
                ((Green * 7 + 128) / 256) * 4  +
                ((Blue  * 3 + 128) / 256);

        /**************************************************************/
        /* Adjust for the Grey slots in the centre of the palette     */
        /**************************************************************/
        if (Temp < 112)
        {
            return(PaletteFudgeTable256[Temp]);
        }
        else
        {
            return(PaletteFudgeTable256[Temp + 32]);
        }
    }
}

/**********************************************************************/
/* NearestDefaultPaletteIndex128()                                    */
/* -------------------------------                                    */
/*  takes an RGB2 value and returns the index of the nearest colour   */
/*  in the default 128 palette.                                       */
/*                                                                    */
/*                                                                    */
/* The default 128 entry palette consists of two parts:               */
/*                                                                    */
/*           Greys in slots 60 to 67.                                 */
/*           Colours in slots 0 to 59, 68 to 127                      */
/*                                                                    */
/*                                                                    */
/* The Colours are made up from:                                      */
/*          5 possible R values evenly spaced from 0 -> 255           */
/*          6 possible G values evenly spaced from 0 -> 255           */
/*          4 possible B values evenly spaced from 0 -> 255           */
/*                                                                    */
/* The Greys have 10 equal R,G + B values evenly spread from 0 -> 255 */
/*      (if you include the 'Colours' BLACK and WHITE)                */
/*                                                                    */
/* The maths envolved and the splitting into Greys and Colours is     */
/* detailed above in the NearestDefaultPaletteIndex256 function.      */
/*                                                                    */
/* If we have a Colour                                                */
/* -------------------                                                */
/*                                                                    */
/* The Nearest R G and B values are:                                  */
/*                                                                    */
/*      RNum = (R * 4 + 128) / 256                                    */
/*      GNum = (G * 5 + 128) / 256                                    */
/*      BNum = (B * 3 + 128) / 256                                    */
/*                                                                    */
/* If you ignore the middle grey slots, the slot number corresponding */
/* to these values is given by:                                       */
/*                                                                    */
/*      Slot = RNum * 24 + GNum * 6 + BNum                            */
/*                                                                    */
/* =>   Slot = ((RNum * 4) + GNum) * 6 + BNum                         */
/*                                                                    */
/*  This can then be adjusted to allow for the Grey slots:            */
/*                                                                    */
/*      if (Slot > 59) Slot += 8                                      */
/*                                                                    */
/* If we have a Grey                                                  */
/* -----------------                                                  */
/*                                                                    */
/* The grey index is given by:                                        */
/*                                                                    */
/* ie   Grey = (G * 9 + 128) / 256                                    */
/*                                                                    */
/* the slot this maps to is given by                                  */
/*                                                                    */
/*      if (Grey == 0)                                                */
/*          Slot = 0;       -- ie BLACK                               */
/*      else if (Grey == 9)                                           */
/*          Slot = 127;     -- ie WHITE                               */
/*      else                                                          */
/*          Slot = 59 + Grey                                          */
/*                                                                    */
/* This gives...                                                      */
/**********************************************************************/
ULONG NearestDefaultPaletteIndex128(RGB2* RGBColour)
{
    ULONG   Temp;
    ULONG   Red   = (*(ULONG*)RGBColour & RED_MASK)   >> 16;
    ULONG   Green = (*(ULONG*)RGBColour & GREEN_MASK) >>  8;
    ULONG   Blue  = (*(ULONG*)RGBColour & BLUE_MASK);


    /******************************************************************/
    /* Do we have a grey value or a colour                            */
    /******************************************************************/
    Temp = ( Red * 9 + 128 ) / 256;
    if ( (Temp == ( Green * 9 + 128 ) / 256 ) &&
         (Temp == ( Blue  * 9 + 128 ) / 256 ) )
    {
        /**************************************************************/
        /* We have a Grey value                                       */
        /**************************************************************/
        if (Temp == 0)
        {
            return(PaletteFudgeTable128[0]);            /* BLACK */
        }
        else if (Temp == 9)
        {
            return(PaletteFudgeTable128[127]);          /* WHITE */
        }
        else
        {
            return(PaletteFudgeTable128[Temp + 59]);
        }
    }
    else
    {
        /**************************************************************/
        /* We have a Colour value                                     */
        /**************************************************************/
        Temp =  (((Red   * 4 + 128) / 256) * 6 +
                 ((Green * 5 + 128) / 256) ) * 4 +
                 ((Blue  * 3 + 128) / 256);

        /**************************************************************/
        /* Adjust for the Grey slots in the centre of the palette     */
        /**************************************************************/
        if (Temp > 59)
        {
            return (PaletteFudgeTable128[Temp + 8]);
        }
        else
        {
            return(PaletteFudgeTable128[Temp]);
        }
    }
}

/**********************************************************************/
/* NearestDefaultPaletteIndex64()                                     */
/* ------------------------------                                     */
/*  takes an RGB2 value and returns the index of the nearest colour   */
/*  in the default 64 entry palette.                                  */
/*                                                                    */
/*                                                                    */
/* The default 64 entry palette consists of two parts:                */
/*                                                                    */
/*           Greys in slots 30 to 33.                                 */
/*           Colours in slots 0 to 29, 34 to 63                       */
/*                                                                    */
/*                                                                    */
/* The Colours are made up from:                                      */
/*          4 possible R values evenly spaced from 0 -> 255           */
/*          5 possible G values evenly spaced from 0 -> 255           */
/*          3 possible B values evenly spaced from 0 -> 255           */
/*                                                                    */
/* The Greys are NOT evenly spread. The easiest method for dealing    */
/* with the greys is not first ignore them and then do a nearest      */
/* colour comparison between the RGB passed and each of the 4 Greys   */
/* available.                                                         */
/*                                                                    */
/* The maths envolved detailed above in the                           */
/* NearestDefaultPaletteIndex256 function.                            */
/*                                                                    */
/* To find the nearest colour                                         */
/* --------------------------                                         */
/*                                                                    */
/* The Nearest R G and B values are:                                  */
/*                                                                    */
/*      RNum = (R * 3 + 128) / 256                                    */
/*      GNum = (G * 4 + 128) / 256                                    */
/*      BNum = (B * 2 + 128) / 256                                    */
/*                                                                    */
/* If you ignore the middle grey slots, the slot number corresponding */
/* to these values is given by:                                       */
/*                                                                    */
/*      Slot = RNum * 15 + GNum * 3 + BNum                            */
/*                                                                    */
/* =>   Slot = ((RNum * 5) + GNum) * 3 + BNum                         */
/*                                                                    */
/* This gives...                                                      */
/**********************************************************************/
ULONG NearestDefaultPaletteIndex64(RGB2* RGBColour)
{
    ULONG   ulNearestColour;
    ULONG   ulDiff;
    ULONG   ulGreyEntry;
    ULONG   Red   = (*(ULONG*)RGBColour & RED_MASK)   >> 16;
    ULONG   Green = (*(ULONG*)RGBColour & GREEN_MASK) >>  8;
    ULONG   Blue  = (*(ULONG*)RGBColour & BLUE_MASK);

    /******************************************************************/
    /* Find the nearest colour (ignoring Greys for now)               */
    /******************************************************************/
    ulNearestColour =  (((Red   * 3 + 128) / 256) * 5  +
                       ((Green * 4 + 128) / 256) ) * 3  +
                       ((Blue  * 2 + 128) / 256);

    /******************************************************************/
    /* Adjust for the Grey slots in the centre of the palette         */
    /******************************************************************/
    if (ulNearestColour > 29)
    {
        ulNearestColour += 4;
    }

    /******************************************************************/
    /* Now see if one of the Greys is actually closer than the colour */
    /* we have.                                                       */
    /******************************************************************/
    ulDiff = rgb2_diff(*RGBColour,
         Reduced64DeviceDefaultPalette[PaletteFudgeTable64[ulNearestColour]]);

    for (ulGreyEntry = 30; ulGreyEntry <= 33  ; ulGreyEntry++)
    {
        /**************************************************************/
        /* If difference between this Grey and the passed RGB is less */
        /* than the difference between the Colour calculated and the  */
        /* passed RGB, then return this Grey.                         */
        /**************************************************************/
        if (rgb2_diff(*RGBColour,
               Reduced64DeviceDefaultPalette[PaletteFudgeTable64[ulGreyEntry]])
            < ulDiff)
        {
            /**********************************************************/
            /* The passed colour is nearer to this Grey.              */
            /**********************************************************/
            ulDiff = rgb2_diff(*RGBColour,
               Reduced64DeviceDefaultPalette[PaletteFudgeTable64[ulGreyEntry]]);
            ulNearestColour = ulGreyEntry;
        }
    }

    return(PaletteFudgeTable64[ulNearestColour]);
}

/**********************************************************************/
/*                                                                    */
/* NearestDefaultPhysicalColor finds the RGB in the default physical  */
/* palette which is the closest match to the supplied RGB value.      */
/*                                                                    */
/**********************************************************************/
RGB2 NearestDefaultPhysicalColor (RGB2  RGBColor)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   Diff;                      /* difference of current entry */
    ULONG   MinDiff;                   /* Minimum Difference to date  */
    ULONG   i;                         /* loop variable               */
    RGB2    ClosestRGB;
    ULONG   ClosestIndex;
    PRGB2   DeviceDefaultPalette;
    ULONG   ulDeviceDefaultPaletteSize;

    #ifdef   BPP24
    if (DDT.BitCount == 24)
    {
        /**************************************************************/
        /* The RGB in the hardware only has a limited number of bits  */
        /* so adjust the RGB value to the nearest in the hardware.    */
        /**************************************************************/
        //if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           ClosestRGB.bRed   = (BYTE)RGBColor.bRed;
           ClosestRGB.bBlue  = (BYTE)RGBColor.bBlue;
           ClosestRGB.bGreen = (BYTE)RGBColor.bGreen;
        //}
        //else
        //{
        //   // flip the bits
        //   ClosestRGB.bRed   = (BYTE)RGBColor.bBlue;
        //   ClosestRGB.bBlue  = (BYTE)RGBColor.bRed;
        //   ClosestRGB.bGreen = (BYTE)RGBColor.bGreen;
        //}
        ClosestRGB.fcOptions = 0;
        return( ClosestRGB );
    }
    #endif

    if (DDT.BitCount == 16)
    {
        /**************************************************************/
        /* The RGB in the hardware only has a limited number of bits  */
        /* so adjust the RGB value to the nearest in the hardware.    */
        /**************************************************************/
        ClosestRGB.bRed   = (BYTE)(RGBColor.bRed   & 0xF8);/* 5 red  bits */
        ClosestRGB.bBlue  = (BYTE)(RGBColor.bBlue  & 0xF8);/* 5 blue bits */

        /**************************************************************/
        /* XGA 16bpp has 6 green bits.                                */
        /**************************************************************/
        ClosestRGB.bGreen = (BYTE)(RGBColor.bGreen & 0xFC);/* 6 green bits*/
        ClosestRGB.fcOptions = 0;

        return( ClosestRGB );
    }

    /******************************************************************/
    /* With palette manager the device default palette for the screen */
    /* (OD_DIRECT DCs) will change size as HW slots are allocated to  */
    /* palette manager palettes.  The device default palette for      */
    /* OD_MEMORY DCs will always be the full size 256 entry palette   */
    /* at 8 bits per pel.  At 4 bits per pel the device default       */
    /* palette will always be the 16 entry reduced size device        */
    /* default palette for both cases.                                */
    /******************************************************************/
    if (pdc->DCIDCType == OD_DIRECT)
    {
        DeviceDefaultPalette = DirectDeviceDefaultPalette;
        ulDeviceDefaultPaletteSize = ulDirectDeviceDefaultPaletteSize;
    }
    else
    {
        DeviceDefaultPalette = MemoryDeviceDefaultPalette;
        ulDeviceDefaultPaletteSize = SizeOfHWPalette;
    }

    /******************************************************************/
    /* Note: the VGA uses a cunning algorithm for calculating the     */
    /* nearest color. Ideally we want to improve our code here in     */
    /* a similar way.                                                 */
    /*                                                                */
    /* Several cunning algorithms coming up ...                       */
    /*                                                                */
    /* The routines NearestDefaultPaletteIndex256                     */
    /*              NearestDefaultPaletteIndex128                     */
    /*              NearestDefaultPaletteIndex64                      */
    /* have been created to return the slot number corresponding to   */
    /* the nearest default palette entry for the 256, 128 and 64      */
    /* entry palettes.                                                */
    /*                                                                */
    /* The other palettes need to have there entries searched for     */
    /* the nearest value.                                             */
    /******************************************************************/
    if (DDT.BitCount == 8)
    {
        switch (ulDeviceDefaultPaletteSize)
        {
            case 256:
                /******************************************************/
                /* Calcultae the slot number of the nearest entry and */
                /* look up its RGB value.                             */
                /******************************************************/
                ClosestIndex = NearestDefaultPaletteIndex256(&RGBColor);
                ClosestRGB   = DeviceDefaultPalette[ ClosestIndex ];
                ClosestRGB.fcOptions = 0;
                return( ClosestRGB );

            case 128:
                /******************************************************/
                /* Calculate the slot number of the nearest entry and */
                /* look up its RGB value.                             */
                /******************************************************/
                ClosestIndex = NearestDefaultPaletteIndex128(&RGBColor);
                ClosestRGB   = DeviceDefaultPalette[ ClosestIndex ];
                ClosestRGB.fcOptions = 0;
                return( ClosestRGB );

            case  64:
                /******************************************************/
                /* Calculate the slot number of the nearest entry and */
                /* look up its RGB value.                             */
                /******************************************************/
                ClosestIndex = NearestDefaultPaletteIndex64(&RGBColor);
                ClosestRGB   = DeviceDefaultPalette[ ClosestIndex ];
                ClosestRGB.fcOptions = 0;
                return( ClosestRGB );
        }
    }

    /******************************************************************/
    /* First check for exact match in the device default Palette      */
    /******************************************************************/
    MinDiff = 0xFFFFFFFF;

    for (i = 0; i < ulDeviceDefaultPaletteSize; i++)
    {
        if ( (URGB(RGBColor) & RGB_MASK) ==
             (URGB(DeviceDefaultPalette[i]) & RGB_MASK) )
        {
            ClosestRGB = DeviceDefaultPalette[i];
            MinDiff = 0;
            break;
        }
    }

    /******************************************************************/
    /* If not found then look for closest                             */
    /******************************************************************/
    if (MinDiff > 0)
    {
        for (i = 0; i < ulDeviceDefaultPaletteSize; i++)
        {
            /**********************************************************/
            /* Get difference between our colour and the colour at    */
            /* this index                                             */
            /**********************************************************/
            Diff = rgb2_diff(RGBColor, DeviceDefaultPalette[i]);

            /**********************************************************/
            /* If this is closer than our previous closest then reset */
            /* MinDiff and set ClosestIndex                           */
            /**********************************************************/
            if (Diff < MinDiff)
            {
                MinDiff = Diff;
                ClosestIndex = i;
            }
        }
        /**************************************************************/
        /* we need the actual RGB value of the nearest color          */
        /**************************************************************/
        ClosestRGB = DeviceDefaultPalette[ClosestIndex];
    }   /* end of perfect match not found                             */

    /******************************************************************/
    /* Return the RGB value without any option bits.                  */
    /******************************************************************/
    ClosestRGB.fcOptions = 0;
    return( ClosestRGB );

} /* NearestDefaultPhysicalColor */


/**********************************************************************/
/* InnerNearestDefaultPhysicalIndex finds the index of the entry in   */
/* the supplied default physical palette which is the closest match   */
/* to the supplied RGB value.                                         */
/**********************************************************************/
ULONG InnerNearestDefaultPhysicalIndex(RGB2  RGBColor,
                                       PRGB2 DeviceDefaultPalette,
                                       ULONG ulDeviceDefaultPaletteSize)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   Diff;                      /* difference of current entry */
    ULONG   MinDiff;                   /* Minimum Difference to date  */
    ULONG   i;                         /* loop variable               */
    ULONG   PhyIndex;

    #ifdef   BPP24
    if (DDT.BitCount == 24)
    {
        /**************************************************************/
        /* 16bpp requires massaging to get from the RGB to the index  */
        /**************************************************************/
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           return(RGB24FromPRGB2(&RGBColor));
        }
        else
        {
           return(RGB24FromPRGB2ATT(&RGBColor));
        }
    }
    #endif

    if (DDT.BitCount == 16)
    {
        /**************************************************************/
        /* 16bpp requires massaging to get from the RGB to the index  */
        /**************************************************************/
        return(RGB16FromPRGB2(&RGBColor));
    }

    /******************************************************************/
    /* Note: the VGA uses a cunning algorithm for calculating the     */
    /* nearest color. Ideally we want to improve our code here in     */
    /* a similar way.                                                 */
    /*                                                                */
    /* Several cunning algorithms coming up ...                       */
    /*                                                                */
    /* The routines NearestDefaultPaletteIndex256                     */
    /*              NearestDefaultPaletteIndex128                     */
    /*              NearestDefaultPaletteIndex64                      */
    /*                                                                */
    /* have been created to return the slot number corresponding to   */
    /* the nearest default palette entry for the 256, 128 and 64      */
    /* entry palettes.                                                */
    /*                                                                */
    /* The other palettes need to have there entries searched for     */
    /* the nearest value.                                             */
    /******************************************************************/
    if (DDT.BitCount == 8)
    {
        switch (ulDeviceDefaultPaletteSize)
        {
            case 256:
                /******************************************************/
                /* Calcultae the slot number of the nearest entry     */
                /******************************************************/
                PhyIndex = NearestDefaultPaletteIndex256(&RGBColor);
                return( PhyIndex );

            case 128:
                /******************************************************/
                /* Calculate the slot number of the nearest entry.    */
                /******************************************************/
                PhyIndex = NearestDefaultPaletteIndex128(&RGBColor);

                /******************************************************/
                /* Adjust for the 128 slots that belong to palette    */
                /* manager apps.                                      */
                /******************************************************/
                if (PhyIndex > 63)
                {
                    return(PhyIndex + 128);
                }
                else
                {
                    return(PhyIndex);
                }

            case  64:
                /******************************************************/
                /* Calculate the slot number of the nearest entry     */
                /******************************************************/
                PhyIndex = NearestDefaultPaletteIndex64(&RGBColor);
                /******************************************************/
                /* Adjust for the 192 slots that belong to palette    */
                /* manager apps.                                      */
                /******************************************************/
                if (PhyIndex > 31)
                {
                    return(PhyIndex + 192);
                }
                else
                {
                    return(PhyIndex);
                }
                break;
        }
    }
    /******************************************************************/

    /******************************************************************/
    /* First check for exact match in the device default Palette      */
    /******************************************************************/
    MinDiff = 0xFFFFFFFF;

    for (i = 0; i < ulDeviceDefaultPaletteSize; i++)
    {
        if ( (URGB(RGBColor) & RGB_MASK) ==
             (URGB(DeviceDefaultPalette[i]) & RGB_MASK))
        {
            PhyIndex = i;
            MinDiff = 0;
            break;
        }
    }

    /******************************************************************/
    /* If not found then look for closest                             */
    /******************************************************************/
    if (MinDiff > 0)
    {
        for (i = 0; i < ulDeviceDefaultPaletteSize; i++)
        {
            /**********************************************************/
            /* Get difference between our colour and the colour at    */
            /* this index                                             */
            /**********************************************************/
            Diff = rgb2_diff(RGBColor, DeviceDefaultPalette[i]);

            /**********************************************************/
            /* If this is closer than our previous closest then reset */
            /* MinDiff and set PhyIndex                               */
            /**********************************************************/
            if (Diff < MinDiff)
            {
                MinDiff = Diff;
                PhyIndex = i;
            }
        }
    }   /* end of perfect match not found                             */

    /******************************************************************/
    /* Make any adjustment necessary to take into account that at 8   */
    /* bits per pel the default palette may be split into two halves. */
    /******************************************************************/
    if (   (DDT.BitCount == 8)
        && (PhyIndex >= (ulDeviceDefaultPaletteSize / 2)) )
    {
        PhyIndex =  PhyIndex + (256 - ulDeviceDefaultPaletteSize);
    }

    /******************************************************************/
    /* Return the PhyIndex                                            */
    /******************************************************************/
    return(PhyIndex);

} /* InnerNearestDefaultPhysicalIndex */


/**********************************************************************/
/* NearestDirectDefaultPhysicalIndex finds the index of the entry in  */
/* the current device default physical palette for OD_DIRECT DCs      */
/* which is the closest match to the supplied RGB value.              */
/**********************************************************************/
ULONG NearestDirectDefaultPhysicalIndex(RGB2  RGBColor)
{
    #ifdef   BPP24
    if (DDT.BitCount == 24)
    {
        /**************************************************************/
        /* 24bpp requires massaging to get from the RGB to the index  */
        /**************************************************************/
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           return(RGB24FromPRGB2(&RGBColor));
        }
        else
        {
           return(RGB24FromPRGB2ATT(&RGBColor));
        }
    }
    #endif

    if (DDT.BitCount == 16)
    {
        /**************************************************************/
        /* 16bpp requires massaging to get from the RGB to the index  */
        /**************************************************************/
        return(RGB16FromPRGB2(&RGBColor));
    }

    /******************************************************************/
    /* Return the PhyIndex                                            */
    /******************************************************************/
    return(InnerNearestDefaultPhysicalIndex(RGBColor,
                                            DirectDeviceDefaultPalette,
                                            ulDirectDeviceDefaultPaletteSize));

} /* NearestDirectDefaultPhysicalIndex */


/**********************************************************************/
/* NearestMemoryDefaultPhysicalIndex finds the index of the entry in  */
/* the current device default physical palette for OD_MEMORY DCs      */
/* which is the closest match to the supplied RGB value.              */
/**********************************************************************/
ULONG NearestMemoryDefaultPhysicalIndex(RGB2  RGBColor)
{
    #ifdef   BPP24
    if (DDT.BitCount == 24)
    {
        /**************************************************************/
        /* 24bpp requires massaging to get from the RGB to the index  */
        /**************************************************************/
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           return(RGB24FromPRGB2(&RGBColor));
        }
        else
        {
           return(RGB24FromPRGB2ATT(&RGBColor));
        }
    }
    #endif

    if (DDT.BitCount == 16)
    {
        /**************************************************************/
        /* 16bpp requires massaging to get from the RGB to the index  */
        /**************************************************************/
        return(RGB16FromPRGB2(&RGBColor));
    }

    /******************************************************************/
    /* Return the PhyIndex                                            */
    /******************************************************************/
    return(InnerNearestDefaultPhysicalIndex(RGBColor,
                                            MemoryDeviceDefaultPalette,
                                            (ULONG)SizeOfHWPalette));

} /* NearestMemoryDefaultPhysicalIndex */

/**********************************************************************/
/* NearestDefaultPhysicalIndex finds the index of the entry in the    */
/* default physical palette which is the closest match to the         */
/* supplied RGB value.                                                */
/**********************************************************************/
ULONG NearestDefaultPhysicalIndex(RGB2  RGBColor)
{
    /******************************************************************/
    /* With palette manager the device default palette for the screen */
    /* (OD_DIRECT DCs) will change size as HW slots are allocated to  */
    /* palette manager palettes.  The device default palette for      */
    /* OD_MEMORY DCs will always be the full size 256 entry palette   */
    /* at 8 bits per pel.  At 4 bits per pel the device default       */
    /* palette will always be the 16 entry reduced size device        */
    /* default palette for both cases. We must call off to two        */
    /* different routines which will pass the correct device default  */
    /* palette on to the low level InnerNearestDefaultPysicalIndex    */
    /* function.                                                      */
    /******************************************************************/
    if (pdc->DCIDCType == OD_DIRECT)
    {
#ifdef FIREWALLS
        /**************************************************************/
        /* This is a good place to check that the DCs device default  */
        /* palette pointer is set correctly.                          */
        /**************************************************************/
        if (  (pdc->DCIDeviceDefaultPalette != DirectDeviceDefaultPalette)
           && (pdc->DCIColFormat != LCOLF_PALETTE) )
        {
            haltproc();
        }
#endif /* FIREWALLS */

        return( NearestDirectDefaultPhysicalIndex(RGBColor) );
    }
    else
    {
#ifdef FIREWALLS
        /**************************************************************/
        /* This is a good place to check that the DCs device default  */
        /* palette pointer is set correctly.                          */
        /**************************************************************/
        if (  (pdc->DCIDeviceDefaultPalette != MemoryDeviceDefaultPalette)
           && (pdc->DCIColFormat != LCOLF_PALETTE) )
        {
            haltproc();
        }
#endif /* FIREWALLS */

        return( NearestMemoryDefaultPhysicalIndex(RGBColor) );
    }

} /* NearestDefaultPhysicalIndex */


/**********************************************************************/
/* NearestRealizableIndex finds the index that gives the nearest RGB  */
/* (to the requested one) in the palette that results from realizing  */
/* the logical color table.                                           */
/**********************************************************************/
ULONG NearestRealizableIndex(RGB2  RGBColor)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   Diff;                      /* difference of current entry */
    ULONG   MinDiff;                   /* Minimum Difference to date  */
    ULONG   i;                         /* loop variable               */
    ULONG   RealIndex;
    RGB2    TestRGB;

    /******************************************************************/
    /* First check for exact match in the realizable palette          */
    /******************************************************************/
    MinDiff = 0xFFFFFFFF;

    for (i = 0; i <= pdc->DCIHighIndex; i++)
    {
        if ( pdc->DCIColorTable[i].PhyIndex != CLR_NOPHYINDEX )
        {
            /**********************************************************/
            /* Index is valid, get it from the color table.           */
            /**********************************************************/
            TestRGB = pdc->DCIColorTable[i].LogRGB;
        }
        else
        {
            /**********************************************************/
            /* This is a gap in the color table, get the entry from   */
            /* the device default palette.                            */
            /**********************************************************/
            TestRGB = MemoryDeviceDefaultPalette[i];
        }

        /**************************************************************/
        /* Now see if we match the test RGB exactly.                  */
        /**************************************************************/
        if (TestRGB.bBlue  == RGBColor.bBlue  &&
            TestRGB.bGreen == RGBColor.bGreen &&
            TestRGB.bRed   == RGBColor.bRed)
        {
            RealIndex = i;
            MinDiff = 0;
            break;
        }
    }

    /******************************************************************/
    /* If an exact match not found then look for closest.             */
    /******************************************************************/
    if (MinDiff)
    {
        for (i = 0; i <= pdc->DCIHighIndex; i++)
        {
            if ( pdc->DCIColorTable[i].PhyIndex != CLR_NOPHYINDEX )
            {
                /******************************************************/
                /* Index is valid, get it from the color table.       */
                /******************************************************/
                TestRGB = pdc->DCIColorTable[i].LogRGB;
            }
            else
            {
                /******************************************************/
                /* This is a gap in the color table, get the entry    */
                /* from the device default palette.                   */
                /******************************************************/
                TestRGB = MemoryDeviceDefaultPalette[i];
            }
            /******************************************************/
            /* This is a valid entry in the LCT so use its        */
            /* logical RGB value.                                 */
            /******************************************************/
            Diff = rgb2_diff(RGBColor, TestRGB);

            /**********************************************************/
            /* If this is closer than our previous closest then reset */
            /* MinDiff and set RealIndex                              */
            /**********************************************************/
            if (Diff < MinDiff)
            {
                MinDiff   = Diff;
                RealIndex = i;
            }
        }
    }   /* end of perfect match not found                             */

    /******************************************************************/
    /* Return the value from the realizable palette                   */
    /******************************************************************/
    return(RealIndex);
} /* NearestRealizableIndex */


/******************************************************************/
/* NearestLogicalColor returns the index into the logical color   */
/* table which will generate the nearest color to RGBColor.       */
/*                                                                */
/* Options can specify:                                           */
/* LCOLOPT_REALIZED - the RGB values to be used are those         */
/*                    available after the LCT has been realized.  */
/*                                                                */
/* This is called by QueryColorIndex                              */
/******************************************************************/
ULONG NearestLogicalColor (ULONG     Options,
                           RGB2      RGBColor)
{
    /******************************************************************/
    /* Local variables.                                               */
    /******************************************************************/
    ULONG       i;                     /* loop variable               */
    RGB2        RGBVal;                /* Stores current color        */
    ULONG       Diff;                  /* Stores color difference     */
    ULONG       MinDiff;               /* Stores minimum difference   */
    ULONG       BestIndex;             /* The best index found        */

    /******************************************************************/
    /* Initialise MinDiff to be a jolly big number, bigger than any   */
    /* other MinDiff in the whole wide world                          */
    /******************************************************************/
    MinDiff = 0xFFFFFFFF;

    /******************************************************************/
    /* Pass through all entries in logical color table                */
    /******************************************************************/
    for (i = pdc->DCILowIndex;
         i <= pdc->DCIHighIndex;
         i++)
    {
        if ( pdc->DCIColorTable[i].PhyIndex != CLR_NOPHYINDEX )
        {
            /**********************************************************/
            /* LCT entry is valid                                     */
            /**********************************************************/
            if (fRealizeSupported &&
                (Options & LCOLOPT_REALIZED))
            {
                /******************************************************/
                /* Need to get the RGB value when color table is      */
                /* realized.                                          */
                /* Take the RGB value from the LCT.                   */
                /******************************************************/
                RGBVal = pdc->DCIColorTable[i].LogRGB;
            }
            else
            {
                /******************************************************/
                /* Calculate the RGB value when the table is not      */
                /* realized.                                          */
                /******************************************************/
                /******************************************************/
                /* Take the RGB value from the default palette, using */
                /* the index defined in the LCT.                      */
                /******************************************************/
                /******************************************************/
                /* we have to make a call here                        */
                /* we cant just pick up the value from the HWPalette  */
                /* because we may be in the background so some other  */
                /* app in the foreground may have dumped on top of    */
                /* the default palette entries                        */
                /******************************************************/
                RGBVal = NearestDefaultPhysicalColor(
                                          pdc->DCIColorTable[i].LogRGB);
            }
            /**********************************************************/
            /* Calculate the difference between the two RGB values    */
            /**********************************************************/
            Diff = rgb2_diff(RGBColor,RGBVal);

            if (Diff == 0)
            {
                /******************************************************/
                /* Exact match has been found - set BestIndex and     */
                /* exit loop.                                         */
                /******************************************************/
                BestIndex = i;
                break;
            }
            if (Diff < MinDiff)
            {
                /******************************************************/
                /* This RGB value is the nearest to the desired RGB   */
                /* value so far. Store the difference and current     */
                /* index.                                             */
                /******************************************************/
                MinDiff = Diff;
                BestIndex = i;
            }
        }
    }
    /******************************************************************/
    /* Return the BestIndex                                           */
    /******************************************************************/
    return(BestIndex);
} /* NearestLogicalColor */


/**********************************************************************/
/* SearchRealizedLCTPalette finds the physical index having the       */
/* nearest RGB value to the given RGB, by searching the table of      */
/* values resulting from a LogicalColorTable which has currently been */
/* realized.                                                          */
/*                                                                    */
/* We try and avoid doing a search if at all possible.                */
/**********************************************************************/
ULONG SearchRealizedLCTPalette (RGB2  RGBColor)
{
    /******************************************************************/
    /* Local variables.                                               */
    /******************************************************************/
    ULONG   ulRGB;

    /******************************************************************/
    /* Get the RGB value as a ULONG which makes for easier            */
    /* comparisons. Keep only the color components.                   */
    /******************************************************************/
    ulRGB = URGB(RGBColor) & 0x00ffffff;

    if (ulRGB == 0x00ffffff)
    {
        return(RealizedWhiteIndex);
    }
    else if (ulRGB == 0x00000000)
    {
        return(RealizedBlackIndex);
    }
    else if (ulRGB != ulLastSearched)
    {
        ulIndexLastSearched = InnerSearchRealizedLCTPalette(RGBColor);
        ulLastSearched = ulRGB;
    }

    return(ulIndexLastSearched);

} /* SearchRealizedLCTPalette */

/**********************************************************************/
/* InnerSearchRealizedLCTPalette is used to actually do the search    */
/* (it does not do any caching of last searched values).              */
/**********************************************************************/
ULONG InnerSearchRealizedLCTPalette (RGB2  RGBColor)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   Diff;                      /* difference of current entry */
    ULONG   MinDiff;                   /* Minimum Difference to date  */
    ULONG   i;                         /* loop variable               */
    ULONG   Index;                     /* index of closest match      */

    /******************************************************************/
    /* First check for exact match in the realized LCT.               */
    /******************************************************************/
    for (i = 0; i < SizeOfHWPalette; i++)
    {
        /**************************************************************/
        /* Check for exact matches.                                   */
        /**************************************************************/
        if (RealizedLCTPalette[i].bBlue  == RGBColor.bBlue  &&
            RealizedLCTPalette[i].bGreen == RGBColor.bGreen &&
            RealizedLCTPalette[i].bRed   == RGBColor.bRed)
        {
            return(i);
        }
    }

    /******************************************************************/
    /* If not found then look for closest                             */
    /******************************************************************/
    MinDiff = 0xFFFFFFFF;
    for (i = 0; i < SizeOfHWPalette; i++)
    {
        /**************************************************************/
        /* find the distance between this palette entry and the       */
        /* required color                                             */
        /**************************************************************/
        Diff = rgb2_diff(RGBColor,RealizedLCTPalette[i]);

        /**************************************************************/
        /* If this is closer than our previous closest then reset     */
        /* MinDiff and set Index                                      */
        /**************************************************************/
        if (Diff < MinDiff)
        {
            MinDiff   = Diff;
            Index = i;
        }
    }
    return(Index);
} /* InnerSearchRealizedLCTPalette */


/**********************************************************************/
/* PhyToLogIndex takes a physical index and returns the (first)       */
/* logical index in the current LogicalColorTable or palette which    */
/* will produce that physical index.  If no logical index produces    */
/* the physical index then the value CLR_NOINDEX is returned.         */
/**********************************************************************/
ULONG PhyToLogIndex(ULONG   ulPhyIndex)
{
    ULONG      i;
    #ifdef BPP24
    ULONG      tmpRGB;
    #endif

    if (pdc->DCIColFormat == LCOLF_PALETTE)
    {
        /**************************************************************/
        /* For direct (screen) DCs we must search through the palette */
        /* looking for an entry is mapped to the HW palette slot      */
        /* (given by the physical index).                             */
        /**************************************************************/
        if (pdc->DCIDCType == OD_DIRECT)
        {
            for (i = 0; i<pdc->Palette->usCountStored; i++)
            {
                if ((ULONG)pdc->Palette->entries[i].bCurrent == ulPhyIndex)
                {
                    return(i);
                }
            }
        }
        else
        {
            /**********************************************************/
            /* For memory DCs we always use a one to one mapping so   */
            /* if the index we have is in the correct range then we   */
            /* can just return it.                                    */
            /**********************************************************/
            if (ulPhyIndex < pdc->Palette->usCountStored)
            {
                return(ulPhyIndex);
            }
        }
    }
    else
    {
        /**************************************************************/
        /* The .Phyindex is only really relevant for color bitmaps.   */
        /* Thus we special case mono bitmaps.                         */
        /*                                                            */
        /* Ideally I think the best return values would be CLR_FALSE  */
        /* and CLR_TRUE (pel is 0 or 1) or maybe CLR_BLACK and        */
        /* CLR_WHITE.                                                 */
        /*                                                            */
        /* However the person who raised this as a defect was         */
        /* expecting CLR_BACKGROUND and CLR_NEUTRAL to be returned.   */
        /*                                                            */
        /* Thus we return CLR_NEUTRAL    if the pel is 0,             */
        /*                CLR_BACKGROUND if the pel is 1.             */
        /**************************************************************/
        if (pdc->DCISelListEntry->Info.BitCount == 1)
        {
            return((ulPhyIndex == 0) ? CLR_NEUTRAL
                                     : CLR_BACKGROUND);
        }

        /**************************************************************/
        /* Search through the logical color table to find the entry   */
        /* which maps to the physical index.                          */
        /**************************************************************/

        for (i=0; i<pdc->DCIColTabSize; i++)
        {
            #ifdef BPP24
            if (pdc->DCISelListEntry->Info.BitCount == 24)
            {
               // @DMS I can change the table or change the way we look at
               // at the table. I think that this is safer. !!!
               ulPhyIndex &= 0x00FFFFFF;
               tmpRGB  = *(PULONG)(&pdc->DCIColorTable[i].LogRGB);
               if (tmpRGB == ulPhyIndex)
               {
                   return(i);
               }
            }
            else
            {
               if (pdc->DCIColorTable[i].PhyIndex == ulPhyIndex)
               {
                   return(i);
               }
            }
            #else
            if (pdc->DCIColorTable[i].PhyIndex == ulPhyIndex)
            {
                return(i);
            }
            #endif
        }
    }

    return(CLR_NOINDEX);

} /* PhyToLogIndex */




/**********************************************************************/
/* ExactDefaultPhysicalIndex searches the current default physical    */
/* palette and returns the index of the RGB entry which matches the   */
/* supplied RGB exactly.  If the exact match does not exist then it   */
/* returns PAL_ERROR (-1).  This routine is only designed to be       */
/* called at 4 and 8 bits per pel.                                    */
/**********************************************************************/
ULONG ExactDefaultPhysicalIndex(ULONG RGBColor)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG   i;                         /* loop variable               */
    ULONG   PhyIndex;
    PRGB2   DeviceDefaultPalette;
    ULONG   ulDeviceDefaultPaletteSize;

#ifdef FIREWALLS
    if (   (pdc->DCISelListEntry->Info.BitCount != 4)
        && (pdc->DCISelListEntry->Info.BitCount != 8))
    {
        haltproc();
    }
#endif /* FIREWALLS */

    /******************************************************************/
    /* With palette manager the device default palette for the screen */
    /* (OD_DIRECT DCs) will change size as HW slots are allocated to  */
    /* palette manager palettes.  The device default palette for      */
    /* OD_MEMORY DCs will always be the full size 256 entry palette   */
    /* at 8 bits per pel.  At 4 bits per pel the device default       */
    /* palette will always be the 16 entry reduced size device        */
    /* default palette for both cases.                                */
    /******************************************************************/
    if (pdc->DCIDCType == OD_DIRECT)
    {
        DeviceDefaultPalette = DirectDeviceDefaultPalette;
        ulDeviceDefaultPaletteSize = ulDirectDeviceDefaultPaletteSize;
    }
    else
    {
        DeviceDefaultPalette = MemoryDeviceDefaultPalette;
        ulDeviceDefaultPaletteSize = SizeOfHWPalette;
    }

    /******************************************************************/
    /* Note: the VGA uses a cunning algorithm for calculating the     */
    /* nearest color. Ideally we want to improve our code here in     */
    /* a similar way.                                                 */
    /******************************************************************/

    /******************************************************************/
    /* Search the palette for an exact match. We search the last 8,   */
    /* followed by the first 8, followed by the central portion       */
    /* because the 16 nearest default colors are stored in these      */
    /* locations. This should optimize for the most common colors.    */
    /******************************************************************/
    PhyIndex = PAL_ERROR;

    for (i = ulDeviceDefaultPaletteSize-8; i < ulDeviceDefaultPaletteSize; i++)
    {
        if ( (URGB(RGBColor) & RGB_MASK) ==
             (URGB(DeviceDefaultPalette[i]) & RGB_MASK))
        {
            PhyIndex = i;
            break;
        }
    }
    if (PhyIndex == PAL_ERROR)
    {
        for (i = 0; i < ulDeviceDefaultPaletteSize-8; i++)
        {
            if ( (URGB(RGBColor) & RGB_MASK) ==
                 (URGB(DeviceDefaultPalette[i]) & RGB_MASK))
            {
                PhyIndex = i;
                break;
            }
        }
    }

    /******************************************************************/
    /* Make any adjustment necessary to take into account that at 8   */
    /* bits per pel the default palette may be split into two halves. */
    /******************************************************************/
    if (   (PhyIndex != PAL_ERROR)
        && (DDT.BitCount == 8)
        && (PhyIndex >= (ulDeviceDefaultPaletteSize / 2)) )
    {
        PhyIndex =  PhyIndex + (256 - ulDeviceDefaultPaletteSize);
    }

    /******************************************************************/
    /* Return the PhyIndex                                            */
    /******************************************************************/
    return(PhyIndex);
}
