;*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.;
;*****************************************************************************/
        page        ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = clip.asm
;*
;* DESCRIPTIVE NAME = Line clipping support. 
;*
;*
;* VERSION      V2.0
;*
;* DATE         06/08/87
;*
;* DESCRIPTION  Inputs are SHORTs.  The clip RECTS is assumed to be
;*              well ordered, and is considered to be inclusive on         
;*              the lower left and exclusive on the upper right.           
;*              Outputs are "normalized", which means they are unsigned    
;*              USHORTs relative to the start point. If the line is        
;*              completely clipped away, we return BX < AX.  An optional   
;*              pair of POINTFXs can be supplied, if so, the result is     
;*              further restricted to be in that range. The input          
;*              RECTS is supplied in the LINESEGMENT structure. Most of    
;*              the output is written into the LINESEGMENT structure.      
;*              Registers Destroyed:                                       
;*                        AX,BX,CX,DX    
;*
;* FUNCTIONS    Public: far_clip_line
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/10/88                     Charles Whitmer [chuckwh]
;*                                  Wrote it.  This is the new clipping 
;*                                  technology!  It handles arbitrarily
;*                                  large SHORT inputs without overflow 
;*                                  or accuracy problems.
;*****************************************************************************/

        .xlist
        include        cmacros.inc
        include        pmgre.inc
        include        driver.inc
        include        polyline.inc
        .list

sBegin        Code
        assumes cs,Code

        assumes ds,nothing
        assumes es,nothing

;/***************************************************************************
;*
;* FUNCTION NAME = far_clip_line
;*
;* DESCRIPTION   = Clips a line segment to a RECTS. 
;*                 Inputs are SHORTs.  The clip RECTS is assumed to be        
;*                 well ordered, and is considered to be inclusive on         
;*                 the lower left and exclusive on the upper right.           
;*                 Outputs are "normalized", which means they are unsigned    
;*                 USHORTs relative to the start point. If the line is        
;*                 completely clipped away, we return BX < AX.  An optional   
;*                 pair of POINTFXs can be supplied, if so, the result is     
;*                 further restricted to be in that range. The input          
;*                 RECTS is supplied in the LINESEGMENT structure. Most of    
;*                 the output is written into the LINESEGMENT structure.      
;*                 Registers Destroyed:                                       
;*                        AX,BX,CX,DX    
;*
;* INPUT         = (BX,CX) - (DI,SI) = the unclipped line   
;*                 SS:BP ==> lsg                            
;*                     lsg_rcsClip = RECTS to clip to       
;*                 ES:DX ==> aptfx  (DI = FFFF if null)     
;* OUTPUT        = None
;*
;* RETURN-NORMAL = In the LINESEGMENT structure:                        
;*                     [xA,xB] = inclusive normalized major coordinate range
;*                     cdx = abs(normalized major coordinate)           
;*                     cdy = abs(normalized minor coordinate)           
;*                     fsLineFlags = LF_ flags                          
;*                     (xStart,yStart) = unclipped start point          
;*                 DI = cdx                                             
;*                 SI = cdy                                             
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc        far_clip_line,<FAR,PUBLIC,NODATA,NONWIN>    ;!!! Don't mess with BP !!
cBegin
        mov        [bp].lsg_cdx,dx         ; ES:cdx => POINTFX
        mov        [bp].lsg_fsLineFlags,0
;/*
;** make sure the line goes left to right
;*/
        cmp        bx,di
        jle        is_left_to_right
        xchg        bx,di
        xchg        cx,si
        or        [bp].lsg_fsLineFlags,LF_LEFT_XCHG
is_left_to_right:

;/*
;** record the start position
;*/
        mov        [bp].lsg_xStart,bx
        mov        [bp].lsg_yStart,cx

;/*
;** load y clipping, normalize y coordinates relative to y1
;*/
        mov        ax,[bp].lsg_rcsClip.rcs_yBottom  ; [AX,DX) is y clip range
        mov        dx,[bp].lsg_rcsClip.rcs_yTop
        sub        ax,cx
        sub        dx,cx
        sub        si,cx
        jge        y_is_unsigned
        neg        si                        ; make cdy positive
        neg        ax                        ; retain inclusive/exclusive
        inc        ax                        ;   properties while flipping
        neg        dx
        inc        dx
        xchg        ax,dx                        ; [AX,DX) is y clip range
        or        [bp].lsg_fsLineFlags,LF_Y_FLIP + LF_VERTICAL_FLIP
y_is_unsigned:

;/*
;** load x clipping, normalize x coordinates relative to x1
;*/
        neg        bx
        add        di,bx
        mov        cx,[bp].lsg_rcsClip.rcs_xRight         ; [BX,CX) is x clip range
        add        cx,bx
        add        bx,[bp].lsg_rcsClip.rcs_xLeft

;/*
;** everything is unsigned, make it x-major
;*/
        cmp        si,di
        jbe        we_are_x_major
        xchg        si,di
        xchg        ax,bx
        xchg        cx,dx
        or        [bp].lsg_fsLineFlags,LF_XY_XCHG
we_are_x_major:

;/*
;** adjust the x clipping for overflow
;*/
        cmp        cx,bx                        ; if not well ordered, the lower one
        jae        x_well_ordered               ; must have been negative
        xor        bx,bx                        ; => round it up to zero
x_well_ordered:

;/*
;** clipping on the right is determined by the upper limit
;*/
        cmp        cx,di
        jbe        @F
        lea        cx,[di][1]
@@:        cmp        cx,bx
        ja        @F
draw_no_pels:
        mov        [bp].lsg_xA,1
        mov        [bp].lsg_xB,0
        jmp        clip_line_done
@@:        dec        cx
        mov        [bp].lsg_xA,bx                         ; x clip => [xA,xB]
        mov        [bp].lsg_xB,cx

;/*
;** recompute   BX = ceil((dx - 2 dy f ) / 2)
;**                                     0
;*/

        mov        bx,di
        or        bl,byte ptr [bp].lsg_fsLineFlags[1]
        .errnz        LF_VERTICAL_FLIP - 100h
        shr        bx,1
        adc        bx,0

;/*
;** perform obvious y bottom clipping (AX is bottom)
;*/
        mov        cx,dx                        ; CX = top (we're going to smash DX)
        cmp        cx,ax                        ; wrap => overflow => no bottom clip
        jb        bottom_y_clipped
        or        ax,ax
        jz        bottom_y_clipped        ; (bottom is below our line)
        cmp        ax,si
        ja        draw_no_pels                ; (bottom is above our line)
        or        si,si
        jz        bottom_y_clipped        ; (horizontal line is in)

;/*
;** compute  x  = floor(s(y - 1/2) + f ) + 1
;**            A                            0
;**
;**              = floor((2 dx y - dx + 2 dy f ) / (2 dy)) + 1
;**                                           0
;**
;**              = floor((dx y - ceil((dx - 2 dy f ) / 2)) / dy) + 1
;**                                               0
;*/

        mul        di
        sub        ax,bx
        sbb        dx,0
        div        si                        ; nifty, eh?
        inc        ax

;/*
;** use this as our lower x limit if it's more restrictive
;*/
        cmp        ax,[bp].lsg_xA
        jb        bottom_y_clipped
        mov        [bp].lsg_xA,ax
bottom_y_clipped:

;/*
;** perform obvious y top clipping
;*/
        cmp        cx,si
        ja        top_y_clipped                ; (top is above our line)
        jcxz        draw_no_pels                ; (horizontal gets totally clipped now)

;/*
;** compute  x  = floor(s(y - 1/2) + f )
;**            B                            0
;**
;**              = floor((2 dx y - dx + 2 dy f ) / (2 dy))
;**                                           0
;**
;**              = floor((dx y - ceil((dx - 2 dy f ) / 2)) / dy)
;**                                               0
;*/

        mov        ax,cx
        mul        di
        sub        ax,bx
        sbb        dx,0
        div        si
;/*
;** use this as our upper x limit if it's more restrictive
;*/
        cmp        ax,[bp].lsg_xB
        ja        top_y_clipped
        mov        [bp].lsg_xB,ax
top_y_clipped:

;/*
;** see if there's any clipping to the POINTFX version of the line
;*/
        mov        bx,[bp].lsg_cdx         ; ES:BX => POINTFX
        cmp        bx,-1
        jz        clip_line_done
;/*
;** handle the y-major case
;*/
        test        [bp].lsg_fsLineFlags,LF_XY_XCHG ; test for y-major
        jz        ptfx_x_major
        mov        cx,es:[bx][SIZE POINTFX].ptfx_y.lo ; DX:CX = y2
        mov        dx,es:[bx][SIZE POINTFX].ptfx_y.hi
        mov        ax,es:[bx].ptfx_y.lo                   ; BX:AX = y1
        mov        bx,es:[bx].ptfx_y.hi

;/*     
;** get relative to yStart
;*/     
        sub        bx,[bp].lsg_yStart
        sub        dx,[bp].lsg_yStart
;/*
;** do Y flip
;*/
        test        [bp].lsg_fsLineFlags,LF_Y_FLIP
        jz        do_left_flips
        neg        ax
        adc        bx,0
        neg        bx
        neg        cx
        adc        dx,0
        neg        dx
        jmp        short do_left_flips
;/*
;** handle the x-major case
;*/

ptfx_x_major:
        mov        cx,es:[bx][SIZE POINTFX].ptfx_x.lo ; DX:CX = x2
        mov        dx,es:[bx][SIZE POINTFX].ptfx_x.hi
        mov        ax,es:[bx].ptfx_x.lo                   ; BX:AX = x1
        mov        bx,es:[bx].ptfx_x.hi

;/*
;** get relative to xStart
;*/
        sub        bx,[bp].lsg_xStart
        sub        dx,[bp].lsg_xStart
;/*
;** do left flips
;*/
do_left_flips:
        test        [bp].lsg_fsLineFlags,LF_LEFT_XCHG
        jz        @F
        xchg        ax,cx
        xchg        bx,dx
@@:
;/*
;** take ceil(major1) and floor(major2)
;*/
        neg        ax
        adc        bx,0                        ; BX = ceil(x1), DX = floor(x2)

;/*
;** intersect it in
;*/
        cmp        bx,[bp].lsg_xA
        jb        @F
        mov        [bp].lsg_xA,bx
@@:        cmp        dx,[bp].lsg_xB
        ja        @F
        mov        [bp].lsg_xB,dx
@@:

;/*
;** load the results and get out
;*/
clip_line_done:
        mov        [bp].lsg_cdx,di
        mov        [bp].lsg_cdy,si
cEnd

sEnd        Code

        end
