;*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  Various functions relating to line clipping.
;*
;* FUNCTIONS    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
;*   06/08/87                     Written by Charles Whitmer
;*   10/30/91                     Cliff Levesque [cliffl] Cleanup and convert 
;*                                to 386 and above flat model, protected mode
;*                                32 bit operation.
;*
;*****************************************************************************/

        .386

        .xlist

        include pmgre.inc
        include driver.inc
        include polyline.inc

        .list

        .MODEL FLAT
    
        ASSUME  CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT

        .DATA

        .CODE

;/***************************************************************************
;*
;* FUNCTION NAME = far_clip_line
;*
;* 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:
;*                        EAX,EBX,ECX,EDX
;*
;*
;*                 
;*
;* INPUT         = ( EBX,ECX ) - ( EDI,ESI ) = the unclipped line
;*         
;*                 EBP ==> lsg
;*         
;*                     lsg_rcsClip = RECTS to clip to
;*         
;*                 EDX ==> aptfx  (DI = FFFF if null)
;* OUTPUT        = 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
;*            
;*                 EDI = cdx
;*                 ESI = cdy
;*            
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
ALIGN 4
far_clip_line   PROC    SYSCALL         

        DebugMsg <far_clip_line CLIP CLIFFL>

        ASSUME  ebp:PTR LINESEGMENT

        mov     [ebp].lsg_cdx,edx         ; ES:cdx => POINTFX
        mov     [ebp].lsg_fsLineFlags,0

;/*
;** make sure the line goes left to right
;*/

        cmp     ebx,edi
        jle     is_left_to_right
        xchg    ebx,edi
        xchg    ecx,esi
        or      [ebp].lsg_fsLineFlags,LF_LEFT_XCHG

is_left_to_right:

;/*
;** record the start position
;*/

        mov     [ebp].lsg_xStart,ebx

        mov     [ebp].lsg_yStart,ecx

;/*
;** load y clipping, normalize y coordinates relative to y1
;*/

        mov     eax,[ebp].lsg_rcsClip.rcl_yBottom  ; [AX,DX) is y clip range
        mov     edx,[ebp].lsg_rcsClip.rcl_yTop
        sub     eax,ecx
        sub     edx,ecx
        sub     esi,ecx
        jge     y_is_unsigned
        neg     esi                        ; make cdy positive
        neg     eax                        ; retain inclusive/exclusive
        inc     eax                        ;   properties while flipping
        neg     edx
        inc     edx
        xchg    eax,edx                        ; [AX,DX) is y clip range
        or      [ebp].lsg_fsLineFlags,LF_Y_FLIP + LF_VERTICAL_FLIP

y_is_unsigned:

;/*
;** load x clipping, normalize x coordinates relative to x1
;*/
        neg     ebx
        add     edi,ebx
        mov     ecx,[ebp].lsg_rcsClip.rcl_xRight         ; [BX,CX) is x clip range
        add     ecx,ebx
        add     ebx,[ebp].lsg_rcsClip.rcl_xLeft

;/*
;** everything is unsigned, make it x-major
;*/

        cmp     esi,edi
        jbe     we_are_x_major
        xchg    esi,edi
        xchg    eax,ebx
        xchg    ecx,edx
        or      [ebp].lsg_fsLineFlags,LF_XY_XCHG

we_are_x_major:

;/*
;** adjust the x clipping for overflow
;*/

        cmp     ecx,ebx                        ; if not well ordered, the lower one
        jae     x_well_ordered                ;   must have been negative
        xor     ebx,ebx                        ;   => round it up to zero

x_well_ordered:

;/*
;** clipping on the right is determined by the upper limit
;*/

        cmp     ecx,edi
        jbe     @F
        lea     ecx,[edi][1]
@@:     cmp     ecx,ebx
        ja      @F

draw_no_pels:

        mov     [ebp].lsg_xA,1
        mov     [ebp].lsg_xB,0
        jmp     clip_line_done
ALIGN 4
@@:     dec     ecx
        mov     [ebp].lsg_xA,ebx         ; x clip => [xA,xB]
        mov     [ebp].lsg_xB,ecx

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

        mov     ebx,edi
        or      bl,byte ptr [ebp].lsg_fsLineFlags[1]

        .errnz  LF_VERTICAL_FLIP - 100h

        shr     ebx,1
        adc     ebx,0

;/*
;** perform obvious y bottom clipping (AX is bottom)
;*/

        mov     ecx,edx                        ; CX = top (we're going to smash DX)
        cmp     ecx,eax                        ; wrap => overflow => no bottom clip
        jb      bottom_y_clipped
        or      eax,eax
        jz      bottom_y_clipped        ; (bottom is below our line)
        cmp     eax,esi
        ja      draw_no_pels                ; (bottom is above our line)
        or      esi,esi
        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     edi
        sub     eax,ebx
        sbb     edx,0
        div     esi                        ; nifty, eh?
        inc     eax

;/*
;** use this as our lower x limit if it's more restrictive
;*/

        cmp     eax,[ebp].lsg_xA
        jb      bottom_y_clipped
        mov     [ebp].lsg_xA,eax

bottom_y_clipped:

;/*
;** perform obvious y top clipping
;*/

        cmp        ecx,esi
        ja        top_y_clipped                ; (top is above our line)
        jecxz        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     eax,ecx
        mul     edi
        sub     eax,ebx
        sbb     edx,0
        div     esi

;/*
;** use this as our upper x limit if it's more restrictive
;*/

        cmp     eax,[ebp].lsg_xB
        ja      top_y_clipped
        mov     [ebp].lsg_xB,eax

top_y_clipped:

;/*
;** see if there's any clipping to the POINTFX version of the line
;*/

        mov     ebx,[ebp].lsg_cdx         ; ES:BX => POINTFX

        ASSUME  ebx:PTR POINTFX

        cmp     ebx,-1
        jz      clip_line_done

;/*
;** handle the y-major case
;*/

        test    [ebp].lsg_fsLineFlags,LF_XY_XCHG ; test for y-major
        jz      ptfx_x_major

        movzx   ecx,WORD PTR [ebx][SIZE POINTFX].ptfx_y         ; DX:CX = y2
        movsx   edx,WORD PTR [ebx][SIZE POINTFX].ptfx_y[2]      ; DX:CX = y2

        movzx   eax,WORD PTR [ebx].ptfx_y                        ; BX:AX = y1
        movsx   ebx,WORD PTR [ebx].ptfx_y[2]                        ; BX:AX = y1

;/*
;** get relative to yStart
;*/

        sub     ebx,[ebp].lsg_yStart
        sub     edx,[ebp].lsg_yStart

;/*
;** do Y flip
;*/

        test    [ebp].lsg_fsLineFlags,LF_Y_FLIP
        jz      do_left_flips
        neg     eax
        adc     ebx,0
        neg     ebx
        neg     ecx
        adc     edx,0
        neg     edx
        jmp     do_left_flips
ALIGN 4

;/*
;** handle the x-major case
;*/

ptfx_x_major:

        movzx   ecx,WORD PTR [ebx][SIZE POINTFX].ptfx_x         ; DX:CX = x2
        movsx   edx,WORD PTR [ebx][SIZE POINTFX].ptfx_x[2]      ; DX:CX = x2

        movzx   eax,WORD PTR [ebx].ptfx_x                        ; BX:AX = x1
        movsx   ebx,WORD PTR [ebx].ptfx_x[2]                        ; BX:AX = x1

;/*
;** get relative to xStart
;*/

        sub     ebx,[ebp].lsg_xStart
        sub     edx,[ebp].lsg_xStart

;/*
;** do left flips
;*/

do_left_flips:

        test    [ebp].lsg_fsLineFlags,LF_LEFT_XCHG
        jz      @F
        xchg    eax,ecx
        xchg    ebx,edx
@@:

;/*
;** take ceil(major1) and floor(major2)
;*/

        neg     eax                     ; BX = ceil(x1), DX = floor(x2)
        adc     ebx,0

;/*
;** intersect it in
;*/

        cmp     ebx,[ebp].lsg_xA
        jb      @F
        mov     [ebp].lsg_xA,ebx
@@:     cmp     edx,[ebp].lsg_xB
        ja      @F
        mov     [ebp].lsg_xB,edx
@@:

;/*
;** load the results and get out
;*/

clip_line_done:

        mov     [ebp].lsg_cdx,edi
        mov     [ebp].lsg_cdy,esi

                RET

far_clip_line   ENDP

        end
