/*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.                                */
/*                                                                           */
/*****************************************************************************/
#define XGADEBUG
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDMTRAN                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor functions          */
/*                     NotifyTransformChange                          */
/*                                                                    */
/*   Function        = NotifyTransformChange announces a change in    */
/*                     the conversion from world to device            */
/*                     co-ordinates                                   */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_DDIMISC
#define INCL_GRE_DEVMISC2
#define INCL_GRE_XFORMS
#include <eddinclt.h>

#include <edddcone.h>
#include <edddtypt.h>
#include <eddmextf.h>
#include <eddgextf.h>

#include <edddebug.h>

extern PPFNL            EnginesDispatchTable;

/**********************************************************************/
/* NotifyTransformChange announces a change in the transformation     */
/* from World to Device co-ordinates.                                 */
/* The new rotation/scaling matrix and translation vector are         */
/* provided, together with option flags detailing the simplicity of   */
/* the transformation.                                                */
/**********************************************************************/

DDIENTRY eddm_NotifyTransformChange (HDC        hdc,
                                     ULONG      ArgFlags,
                                     PULONG     ArgTransform,
                                     PDC        pdcArg,
                                     ULONG      FunN)

{
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    POINTL          Coord;            /* Coordinate to be transformed */
    DevRect         PickWindowDevice; /* New device pick window       */

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

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

#ifdef FIREWALLS
    /******************************************************************/
    /* The engine is not setting the MATRIX_UNITS flag when it should */
    /* we will check it for now, but wont need to when this has been  */
    /* fixed.                                                         */
    /* It Should be set if all the matrix entries are -1, 0, or 1     */
    /* (in FIXED notation).                                           */
    /******************************************************************/
    if ( (ArgFlags & MATRIX_SIMPLE) && !(ArgFlags & MATRIX_UNITS))
    {
        PLONG   plCheck = ArgTransform + 1;
        LONG    i;
        BOOL    leave = FALSE;

        for (i = 0; i < 4 ; i++, plCheck++)
        {
            if ((*plCheck != 0xffff0000) &&
                (*plCheck != 0x00000000) &&
                (*plCheck != 0x00010000))
            {
                /******************************************************/
                /* The MATRIX_UNITS flag should not have been set     */
                /* after all..                                        */
                /******************************************************/
                leave = TRUE;
                break;
            }
        }
        if (!leave)
        {
            DebugOutput("XGA : Corrected MATRIX_UNITS flag from PMGRE\r\n");
            ArgFlags |= MATRIX_UNITS;
        }
    }
#endif /* FIREWALLS */

    /******************************************************************/
    /* Set the DCIXFrmSimple flag. If this flag is TRUE then we can   */
    /* avoid calling the engine for coordinate conversions.           */
    /******************************************************************/
    pdc->DCIXFrmSimple = (ArgFlags == (MATRIX_SIMPLE | MATRIX_UNITS));

    /******************************************************************/
    /* Re-convert the pick window to device coordinates and store it  */
    /* in a local variable (so that we can recover if anything goes   */
    /* wrong).                                                        */
    /******************************************************************/
    if ( OK != eddg_Convert( (PULONG) pdc->DCIPickWindowPage,
                             (PULONG) PickWindowDevice,
                             COORD_PAGE,
                             COORD_DEVICE_WORD,
                             2,
                             COM_TRANSFORM
                           )
       )
    {
        /**************************************************************/
        /* eddg_Convert detected an error.                            */
        /**************************************************************/
        LogError(PMERR_INV_COORDINATE);
        goto NOTIFYTRANCHANGE_ERR_EXIT;
    }

    /******************************************************************/
    /* Recalculate the AI current position from the world current     */
    /* position.                                                      */
    /* First set Coord to be the current position in World coords.    */
    /******************************************************************/
    Coord = pdc->DCICurrPosWorld;

    /******************************************************************/
    /* Call the engine to convert the coordinate.                     */
    /******************************************************************/
    if (OK != EnginesDispatchTable[NGreConvert & 0xff](
                                       hdc,
                                       COORD_WORLD,
                                       COORD_DEVICE,
                                       &Coord,
                                       1,
                                       NULL,
                                       NGreConvert) )

    {
        goto NOTIFYTRANCHANGE_ERR_EXIT;
    }

    /******************************************************************/
    /* Check that we are not going to lose any significant            */
    /* bits when we convert Coord from a LONG to a SHORT.             */
    /* We can do this by casting the value to a SHORT, sign-          */
    /* extending it to a LONG, and then comparing the top             */
    /* 16 bits with the original 16 bits. If the upper bits           */
    /* are different then we are going to lose information            */
    /* when converting to a SHORT.                                    */
    /******************************************************************/
    if ( (HIUSHORT(Coord.x) != HIUSHORT((LONG)((SHORT)Coord.x)) ) ||
         (HIUSHORT(Coord.y) != HIUSHORT((LONG)((SHORT)Coord.y)) ) )
    {
        /**************************************************************/
        /* The device coordinate is invalid. Log an error and         */
        /* exit.                                                      */
        /**************************************************************/
        LogError(PMERR_COORDINATE_OVERFLOW);
        goto NOTIFYTRANCHANGE_ERR_EXIT;
    }

    /******************************************************************/
    /* Pass call through the engine.                                  */
    /******************************************************************/
    if (OK != EnginesDispatchTable[NGreNotifyTransformChange & 0xff](
                                                           hdc,
                                                           ArgFlags,
                                                           ArgTransform,
                                                           pdcArg,
                                                           FunN) )
    {
        /**************************************************************/
        /* There was an error in the engine so exit without           */
        /* changing the current position                              */
        /**************************************************************/
        goto NOTIFYTRANCHANGE_ERR_EXIT;
    }

    /******************************************************************/
    /* Everything looks good, so copy the newly calculated values     */
    /* into pdc->                                                     */
    /* First do the new device coordinate pick rectangle.             */
    /******************************************************************/
    pdc->DCIPickWindowDevice[0] = PickWindowDevice[0];
    pdc->DCIPickWindowDevice[1] = PickWindowDevice[1];

    /******************************************************************/
    /* Now copy Coord to DCICurrPosAI, converting from Device to AI   */
    /* coords as we go.                                               */
    /******************************************************************/
    pdc->DCICurrPosAI.X = (SHORT)(Coord.x + (LONG)pdc->DCIOrigin.X);
    pdc->DCICurrPosAI.Y = (SHORT)((LONG)pdc->DCIConvFactor - Coord.y);

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
    return(OK);

NOTIFYTRANCHANGE_ERR_EXIT:
    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
    return(ERROR_ZERO);
}
