/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDILINE
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdi_ClipLine
 *             prdi_OutCode
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#include <prdicone.h>

#define NO_SYS
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef NO_SYS

#include <prdiextf.h>





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdi_ClipLine                                          */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   DevRect  far *ClipRect;   Pointer to clip rectangle to use       */
/*   DevPoint far *Start;      Pointer to start of line before        */
/*                             clipping (on return this will be the   */
/*                             start of the clipped line)             */
/*   DevPoint far *Finish;     Pointer to end of line before clipping */
/*                             (on return this will be the start of   */
/*                             the clipped line)                      */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function clips the line specified by Start and Finish to    */
/*   the rectangle specified by ClipRect.  It uses prdi_Outcode to    */
/*   calculate Cohen-Sutherland outcodes for the original line and    */
/*   then uses these to perform the appropriate clipping.  The clipped*/
/*   line is ALWAYS returned in the same direction as it was before   */
/*   clipping.                                                        */
/*                                                                    */
/*   REFERENCE:                                                       */
/*                                                                    */
/*   Cohen-Sutherland clipping algorithm described in 'Principles Of  */
/*   Interactive Computer Graphics' by W. M. Newman and R. F. Sproull */
/*   pub McGraw-Hill.                                                 */
/*                                                                    */
/**********************************************************************/
#if 0
USHORT pascal prdi_ClipLine ( ClipRect,
                              Start,
                              Finish )

DevRect  far *ClipRect;
DevPoint far *Start;
DevPoint far *Finish;
#endif

USHORT prdi_ClipLine ( DevRect  *ClipRect,                 /* CON3201 */
                       DevPoint *Start,                    /* CON3201 */
                       DevPoint *Finish )                  /* CON3201 */

{
#define TFUNC "prdi_ClipLine"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    DevPoint    Begin;                 /* Working storage for start ..*/
    DevPoint    End;                   /*  .. and finish coordinates  */
                                       /*  during algorithm           */
    SHORT       Xmax;                       /* INCLUSIVE top left boundary */
    SHORT       Ymax;                       /*  of the clip rectangle      */
    USHORT      StartOutcode;          /* Outcode for start point     */
         USHORT      EndOutcode;            /* Outcode for end point       */
    DevPoint    SwapPoint;             /* Temporary swap storage      */
    USHORT      SwapOutcode;           /* Temporary swap storage      */
    BOOL        Swapped;               /* Flag keeps track of whether */
                                       /* line is the same way round  */
                                       /* as when we recieved it      */

    TRACE4(TFUNC, "ClipRect", ClipRect, 2);
    TRACE4(TFUNC, "Start", Start, 1);
    TRACE4(TFUNC, "Finish", Finish, 1);

    /******************************************************************/
    /* Set up the inclusive top right coordinates of the clip         */
    /* rectangles (it is supplied as non-inclusive at the top and to  */
    /* the right).                                                    */
    /******************************************************************/
    Xmax = (*ClipRect)[1].X - 1;
    Ymax = (*ClipRect)[1].Y - 1;

    /******************************************************************/
    /* Initialize Begin and End to the start and finish of the line   */
    /* to be clipped.                                                 */
    /******************************************************************/
    Begin = *Start;
    End = *Finish;
    Swapped = FALSE;

    /******************************************************************/
    /* Go into a loop which will be exited from by a return when the  */
    /* line has been fully clipped or trivially rejected.             */
    /******************************************************************/
    for (;;)
    {
        /**************************************************************/
        /* First, obtain the Cohen-Sutherland outcodes for the        */
        /* current Begin and End points of the line.                  */
        /**************************************************************/
        StartOutcode = prdi_Outcode(Begin, ClipRect);
        EndOutcode   = prdi_Outcode(End, ClipRect);

        /**************************************************************/
        /* If the current Begin and End coordinates both lie inside   */
        /* the clip rectangle then the line can be accepted and we    */
        /* can exit from the loop after ensuring that we return the   */
        /* line in the same direction as we recieved it.              */
        /**************************************************************/
        if ((StartOutcode == 0) && (EndOutcode == 0))
        {
            if (Swapped)
            {
                *Start = End;
                *Finish = Begin;
            }
            else
            {
                *Start = Begin;
                *Finish = End;
            }

            TRACE4(TFUNC, "Accept line", NULL, 0);
            TRACE4(TFUNC, "Start", Start, 1);
            TRACE4(TFUNC, "Finish", Finish, 1);
            return (OK);
        }

        /**************************************************************/
        /* If the entire line is outside the clip region then we can  */
        /* reject it and return the appropriate code.                 */
        /**************************************************************/
        if ((StartOutcode & EndOutcode) != 0)
        {
            TRACE4(TFUNC, "trivial reject",FNULL,0);
            return(ERROR_ZERO);
        }

        /**************************************************************/
        /* The remainder of the algorithm relies on at least the      */
        /* starting point of the line being outside the clip region   */
        /* so if this is not the case then swap the start and end     */
        /* points.                                                    */
        /**************************************************************/
        if (StartOutcode == 0)
        {
            TRACE4(TFUNC, "swap points",FNULL,0);

            SwapPoint = Begin;
            Begin = End;
            End = SwapPoint;

            SwapOutcode = StartOutcode;
            StartOutcode = EndOutcode;
            EndOutcode = SwapOutcode;

            Swapped = !Swapped;
        }

        /**************************************************************/
        /* Subdivide the line to exclude a part of the line which is  */
        /* outside the clip region.  This may not exclude all the     */
        /* sections of the line which are outside the clip region so  */
        /* this section will be repeated until the outcodes           */
        /* determined at the start of the loop indicate the line is   */
        /* wholly inside the clip region.                             */
        /**************************************************************/
        if (StartOutcode & CS_ABOVE)
        {
             TRACE4(TFUNC, "Clip above",FNULL,0);

             /*********************************************************/
             /* If the starting point is above the clip region then   */
             /* determine a new starting point on the top line of the */
             /* clip region (or an extension of it left or right) by  */
             /* dividing the line proportionally.  eg NewY = Y        */
             /* coordinate of top line of clip region NewX = (OldX +  */
             /* (Xlength)*((YlengthAboveNewY / Ylength)) The rest of  */
             /* the clipping is done using the same method of         */
             /* proportionally dividing the line to find a position   */
             /* on one of the lines (or an extension of one of the    */
             /* lines).                                               */
             /*********************************************************/
             if (Begin.X != End.X)
             {
                        Begin.X = (USHORT)((int)Begin.X +
                                   (LONG)((LONG)((SHORT)End.X - (int)Begin.X) *
                                    (LONG)(Ymax - (SHORT)Begin.Y)) /
                                         (SHORT)((SHORT)End.Y - (int)Begin.Y));
             }
             Begin.Y = Ymax;
        }
        /*.. if (StartOutcode & CS_ABOVE) ............................*/

        else if (StartOutcode & CS_BELOW)
        {
             /*********************************************************/
             /* Starting point below clip region                      */
             /*********************************************************/
             TRACE4(TFUNC, "clip below",FNULL,0);
             if (Begin.X != End.X)
             {
                         Begin.X = (SHORT)((SHORT)Begin.X +
                      (LONG)((LONG)((SHORT)End.X - (SHORT)Begin.X) *
                    (LONG)((SHORT)(*ClipRect)[0].Y - (SHORT)Begin.Y)) /
                       (SHORT)((SHORT)End.Y - (SHORT)Begin.Y));
             }
             Begin.Y = (*ClipRect)[0].Y;
        }
        else
        if (StartOutcode & CS_RIGHT)
        {
             /*********************************************************/
             /* Starting point to the right of the clip region        */
             /*********************************************************/
             TRACE4(TFUNC, "clip right",FNULL,0);
             if (Begin.Y != End.Y)
                 Begin.Y = (USHORT)((int)Begin.Y +
                       (long)((long)((int)End.Y - (int)Begin.Y) *
                       (long)(Xmax - (int)Begin.X)) /
                       (int)((int)End.X - (int)Begin.X));
             Begin.X = Xmax;
        }
        else
        if (StartOutcode & CS_LEFT)
        {
             /*********************************************************/
             /* Starting point to the left of the clip region         */
             /*********************************************************/
             TRACE4(TFUNC, "clip left",FNULL,0);

             if (Begin.Y != End.Y)
                 Begin.Y = (USHORT)((int)Begin.Y +
                       (long)((long)((int)End.Y - (int)Begin.Y) *
                       (long)((int)(*ClipRect)[0].X - (int)Begin.X)) /
                       (int)((int)End.X - (int)Begin.X));
             Begin.X = (*ClipRect)[0].X;
        }
        TRACE4(TFUNC, "Begin",&Begin,1);
        TRACE4(TFUNC, "End",&End,1);
    }
    /*.. for (;;) ....for ever........................................*/

} /* prdi_ClipLine */
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdi_Outcode                                           */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   DevPoint Point;           The point to determine the outcode for */
/*   DevRect far * ClipRect;   Pointer to the clip rectangle          */
/*                                                                    */
/*   DESCRIPTION                                                      */
/*                                                                    */
/*   This function returns a Cohen-Sutherland outcode for the point   */
/*   passed to it with respect to the clip rectangle indicated by     */
/*   ClipRect.                                                        */
/*                                                                    */
/**********************************************************************/
#if 0
USHORT pascal prdi_Outcode ( Point,
                             ClipRect )

DevPoint      Point;
DevRect far * ClipRect;
#endif

USHORT prdi_Outcode ( DevPoint  Point,                     /* CON3201 */
                      DevRect  *ClipRect )                 /* CON3201 */

{
#define TFUNC "prdi_Outcode"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    USHORT Outcode;        /* The outcode calculated                  */

    /******************************************************************/
    /* First set up either the left or right bits of the outcode if   */
    /* required.                                                      */
    /******************************************************************/
    if ((int)(Point.X)  < (int)((*ClipRect)[0].X))
        Outcode = CS_LEFT;
    else if ((int)(Point.X)  >=  (int)((*ClipRect)[1].X))
        Outcode = CS_RIGHT;
         else
        Outcode = 0;

    /******************************************************************/
    /* Then combine the code already calculated with the above and    */
    /* below outcodes if required.                                    */
    /******************************************************************/
    if ((int)(Point.Y)  < (int)((*ClipRect)[0].Y))
        Outcode |= CS_BELOW;
    else if ((int)(Point.Y)  >=  (int)((*ClipRect)[1].Y))
             Outcode |= CS_ABOVE;

    TRACE4(TFUNC, "exit: outcode",&Outcode,1);
    return(Outcode);

} /* prdi_Outcode */

#undef TFUNC


