;*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 = MAJOR01.ASM
;*
;* DESCRIPTIVE NAME = Set and get attribute orders.
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/07/87
;*
;* DESCRIPTION  Set and get attribute orders.
;*
;* FUNCTIONS    ComputeBounds 
;*              GetCurrentPosition 
;*              SetCurrentPosition 
;*              DisjointLines
;*              PolyLine 
;*              PolyLineCorrelate 
;*
;* 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/07/87                     Written by Hock Lee [hockl]
;*   02/11/88                     Martin Picha [martinpi]
;*                                Made it check COM_TRANSFORM
;*   07/18/87                     Hock Lee [hockl] Modified for new DDI.
;*   06/20/87                     Charles Whitmer [chuckwh]
;*                                Rewrote it to check the DDC_CUR_POS_INVALID
;*                                flag.
;*   05/07/87                     Hock Lee [hockl] Wrote GetCurrentPosition
;*   06/15/88                     Kent Settle [kentse]
;*                                Don't set the current position until we
;*                                know the conversion worked.
;*   01/13/88                     Hock Lee [hockl]
;*                                Rewrote it to keep current position in both
;*                                SCREEN and WORLD coordinates.
;*   07/18/87                     Hock Lee [hockl] Modified for new DDI.
;*   06/20/87                     Charles Whitmer [chuckwh]
;*                                Rewrote it according to the new convention
;*                                which uses the INVALID flag.
;*   05/07/87                     Hock Lee [hockl] Wrote SetCurrentPosition
;*   06/18/89                     Lee A. Newberg [leen]
;*                                Created DisjointLines.
;*   05/08/89                     Lee A. Newberg [leen]
;*                                Correlates for INFO DC's too.  PTR HM377.
;*   08/18/87                     Hock Lee [hockl]
;*                                Used ddc_pat_color_ours for
;*                                drawmode.TextColor.
;*   07/30/87                     Lee A. Newberg [leen]
;*                                Gets the engine to do accumulation of areas,
;*                                clipareas, and strokes
;*   07/18/87                     Hock Lee [hockl] Modified for new DDI.                       
;*   05/11/87                     Kent Settle [kentse] Created PolyLine                            
;*   05/23/66                     Charles Whitmer [chuckwh] Wrote ComputeBounds
;*   06/18/89                     Lee A. Newberg [leen]
;*                                Supports DisjointLines correlation.
;*   05/10/88                     Charles Whitmer [chuckwh]
;*                                Wrote PolyLineCorrelate
;*
;*****************************************************************************/

        .286p
        .xlist
        include cmacros.inc
INCL_GRE_LINES          equ                      1
INCL_GRE_DEVSUPPORT     equ                      1
INCL_GRE_DEVMISC3       equ                      1
INCL_DEV                equ                      1
INCL_DDICOMFLAGS        equ                      1
INCL_DDIPATHS           equ                      1
        include pmgre.inc
        include driver.inc
        include drawline.inc
        include polyline.inc
        include assert.mac
        include njmp.mac
        .list

        errcode <INV_LENGTH_OR_COUNT,BITMAP_NOT_SELECTED>

        externFP        DosGetSeg

        externA         SCREEN_CX
        externA         SCREEN_CY

sBegin  Data
        externB ddcInit
        externD pfnDefSetCurrentPosition
        externD pfnDefDisjointLines
        externD pfnDefPolyLine
sEnd    Data

        externFP        far_exclude                   ; CURSORSC.ASM
        externFP        far_unexclude                 ; CURSORSC.ASM
        externFP        far_recalc_correlate_rect     ; MAJOR0B.ASM
        externFP        far_do_polylines              ; POLYLINE.ASM
        externFP        far_clip_line                 ; CLIP.ASM

sBegin  Code
        assumes cs,Code

        externNP        enter_driver
        externNP        leave_driver
        externNP        MakeColorsValid
        externNP        convert_world_screen
        externNP        convert_screen_world
        externNP        InnerAccumulateBounds
        externNP        PropagateSysClrChange        ; COLORTBL.ASM

        externW         CodeData
page

;/***************************************************************************
;*
;* FUNCTION NAME = GetCurrentPosition
;*
;* DESCRIPTION   = Returns the current position as an x,y coordinate pair: 
;*                 (s32_x, s32_y).
;*                
;*                 Return values:                                                            *
;*                   As specified for the GreGetCurrentPosition function.                    *
;*                 Registers Destroyed:
;*                   AX,BX,CX,DX,ES,GS
;*
;* INPUT         = lpXY    Specifies the return address for the data. 
;* OUTPUT        = None
;*
;* RETURN-NORMAL = AX = 1
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        check   GetCurrentPosition,<hdc,pptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   GetCurrentPosition,<PUBLIC,FAR,NODATA>,<di,si>

        parmD   hdc
        parmD   lpXY
        parmD   hddc
        parmD   FunN

cBegin
        cld
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo                        ; DS:SI --> ddc
        mov     dx,si
        call    enter_driver
        jc      gcp_exit_no_lock                  ; DX:AX = 0 on error

        les     di,lpXY                           ; ES:DI = lpXY
        assumes es,nothing

        CPUMode 386
        lgs     si,[si].ddc_prddc                 ; GS:SI = RDDC
        assumes gs,nothing
        rddc?   gs,si

        test    FunN.hi,COM_TRANSFORM
        jz      we_should_get_device_coordinates

        lea     si,[si].rddc_ptlWorldPos
        movs    dword ptr es:[di],dword ptr gs:[si]
        movs    dword ptr es:[di],dword ptr gs:[si]
        .errnz  (size POINTL)-8

        jmp     short GetCurrentPosition_exit

we_should_get_device_coordinates:
        lea     si,[si].rddc_ptsCurPos.pts_x
        lods    word ptr gs:[si]
        cwde
        stosd

        lods    word ptr gs:[si]
        cwde
        stosd
        .errnz  rddc_ptsCurPos.pts_y - rddc_ptsCurPos.pts_x - 2
        CPUMode 286

GetCurrentPosition_exit:

        mov     ax,1
        cwd
        call    leave_driver
gcp_exit_no_lock:
        fw_zero <es,cx>
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = SetCurrentPosition 
;*
;* DESCRIPTION   = 
;*        Sets the current x,y position to the specified value and resets the line 
;*        type sequence.                                                           
;*                                                                                 
;*        If Area accumulation is in progress, then the Engine's Area code will    
;*        have seen this call already.  The Engine takes care of closure lines,    
;*        etc.                                                                     
;*                                                                                 
;*        The driver is responsible for keeping the current position.  It must be  
;*        maintained in WORLD coordinates so that there is no round off error      
;*        between a SetCurrentPosition and a GetCurrentPosition.                   
;*                                                                                 
;*        Both WORLD and SCREEN coordinates of current position are always kept up 
;*        to date!                                                                 
;*
;*        Registers Destroyed:
;*              AX,BX,CX,DX,ES,GS
;*
;* INPUT         = lpXY    Points to the integer values (s32_x, s32_y) of the
;*                         new current position.
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = AX = 0 
;*
;**************************************************************************/

        check   SetCurrentPosition,<hdc,pptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   SetCurrentPosition,<PUBLIC,FAR,NODATA>,<di,si>

        parmD   hdc
        parmD   lpXY
        parmD   hddc
        parmD   FunN

cBegin

; Check if accumulation is set
        test    seg_FunN,COM_AREA + COM_PATH
        jz      no_accum
        cleanframe
        mov     es,CodeData
        assumes es,Data
        jmp     pfnDefSetCurrentPosition

        assumes ds,nothing
        assumes es,nothing

no_accum:
        cld
        mov     ds,CodeData
        assumes ds,Data

        mov     si,hddc.lo                        ; DS:SI = DDC
        mov     dx,si
        call    enter_driver
        njc     scp_exit_no_lock                  ; DX:AX = 0 on error

        les     di,lpXY
        assumes es,nothing

;/*
;**  set the DDC_FIRST_PEL bit of the flags in the DDC.
;*/

        or      [si].ddc_fb,DDC_FIRST_PEL

;/*
;**  reset the line type sequence
;*/

        xor     ax,ax
        mov     word ptr [si].ddc_la.la_bError,ax
        .errnz  la_bMask  - la_bError - 1
        .errnz  la_bStepX - la_bMask  - 1

;/*
;**  move new WORLD position to DDC
;*/

        test    seg_FunN,COM_TRANSFORM            ; FunN - MSW is commands
        jz      pt_is_screen


;*/


;/*
;**  perform transformation in local space
;**  so we don't wipe out what we were passed in.
;*/

        push    es:[di][6]
        push    es:[di][4]
        push    es:[di][2]
        push    es:[di][0]
        .errnz  SIZE POINTL - 8

update_screen_position:
        mov     bx,sp
        farPtr  lp_point,ss,bx
        cCall   convert_world_screen,<lp_point,1> ; DS:SI = DDC
        pop     dx
        add     sp,2                              ; checked by convert_world_screen
        pop     cx
        add     sp,2                              ; checked by convert_world_screen
        .errnz  SIZE POINTL - 8
        or      ax,ax                             ; check return code from convert.
        jz      SetCurrentPosition_exit           ; exit if error.

;/*
;**  we now know the convert worked, so set the new current position now.
;*/

        CPUMode 386
        lgs     si,[si].ddc_prddc                  ; GS:SI = RDDC
        assumes gs,nothing
        rddc?   gs,si

        mov     gs:[si].rddc_ptsCurPos.pts_x,dx
        mov     gs:[si].rddc_ptsCurPos.pts_y,cx

        les     di,lpXY
        assumes es,nothing

        mov     ebx,es:[di].ptl_y
        mov     ecx,es:[di].ptl_x
        mov     gs:[si].rddc_ptlWorldPos.ptl_y,ebx
        mov     gs:[si].rddc_ptlWorldPos.ptl_x,ecx
        CPUMode 286
        jmp     short SetCurrentPosition_exit


;/*
;**  move new SCREEN position to DDC
;*/

pt_is_screen:
        CPUMode 386
        lgs     bx,[si].ddc_prddc                 ; GS:BX = RDDC
        assumes gs,nothing
        rddc?   gs,bx
        mov     ax,es:[di].ptl_y.lo
        mov     gs:[bx].rddc_ptsCurPos.pts_y,ax
        cwde
        mov     gs:[bx].rddc_ptlWorldPos.ptl_y,eax

        mov     ax,es:[di].ptl_x.lo
        mov     gs:[bx].rddc_ptsCurPos.pts_x,ax
        cwde
        mov     gs:[bx].rddc_ptlWorldPos.ptl_x,eax

;/*
;**  transform NewPosition to WORLD coordinates
;**  dispatch to engine?!!!
;*/

        lea     bx,[bx].rddc_ptlWorldPos
        farPtr  lp_point,gs,bx
        cCall   convert_screen_world,<lp_point,1> ; ds:si = ddc
        CPUMode 286

SetCurrentPosition_exit:
        cwd
        call    leave_driver
scp_exit_no_lock:
        fw_zero <es,cx>
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = PolyLine 
;*
;* DESCRIPTION   =  Polyline initializes things for the line drawing routines. 
;*                  If the lines are being drawn to the EGA, then the EGA is 
;*                  initialized as necessary and the exclusion area is handled.
;*                  If the lines are being written to a bitmap, information about 
;*                  the bitmap is loaded.  Necessary tables and pointers are set 
;*                  up depending on line style and destination device. When all 
;*                  of the necessary initialization is complete, we jump to        
;*                  polyline_loop which does the DDA and the line drawing.                  
;*
;*                  Registers Destroyed:
;*                        AX,BX,CX,DX,flags.
;*                  Registers Preserved:
;*                        DI,SI,DS,BP
;*
;*                  Calls:
;*                         exclude
;*                         polyline_set_ega_for_one_pass
;*                         polyline_set_ega_for_two_pass
;*                         unexclude
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = AX = 1 if polylines drawn.     
;* RETURN-ERROR  = AX = 0 if polylines not drawn. 
;*
;**************************************************************************/

BATCH_POINTS    equ     100
        .errnz  BATCH_POINTS AND 1

        assumes ds,nothing
        assumes es,nothing

        check   PolyLine,     <hdc,pptl,cptl,hddc,ulFunN>
        check   DisjointLines,<hdc,pptl,cptl,hddc,ulFunN>

        public  DisjointLines
DisjointLines:
        errn$   PolyLine

cProc   PolyLine,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   lpPolyXY
        parmD   PolyN
        parmD   hddc
        parmD   FunN
        localW  flags
        localW  cLines
        localW  returnvalue
        localW  fHits
        localW  wStylePosition
        localV  rcsBounds,%(SIZE RECTS)
        localV  aptl,%((BATCH_POINTS+1) * SIZE POINTL)
cBegin

        xor     ax,ax
        mov     fHits,ax

;/*
;**  send to Engine if accumulating
;*/

        test    FunN.hi,COM_AREA + COM_PATH
        jnz     polylines_to_simulation

;/*
;**  send to Engine if clipping is complex
;*/

        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo                        ; SI = DDC
        mov     dx,si
        call    enter_driver
        njc     pl_exit_no_lock                   ; DX:AX = 0 on error
        cmp     [si].ddc_crcsClip,2               ; only valid inside semaphore!
        jae     leave_and_simulate                ; continue if less than 2 clip rects
        cmp     [si].ddc_la.la_sWidth,1           ; Send back cosmetic wideline to engine
        jle     polyline_we_can_do
leave_and_simulate:
        call    leave_driver

;/*
;**  bop off to the simulation
;*/

polylines_to_simulation:
        mov     es,CodeData
        assumes es,Data
        cmp     FunN.lo,off_PolyLine
        jnz     @F
        cleanframe
        assumes ds,nothing
        jmp     pfnDefPolyLine                    ;Pass it back to the engine
@@:
        cleanframe
        assumes ds,nothing
        jmp     pfnDefDisjointLines               ;Pass it back to the engine

;/*
;**  we will draw it!
;*/

        assumes ds,Data
        assumes es,nothing

polyline_we_can_do:
        mov     flags,0

        mov     ax,[si].ddc_iSysClr
        lea     di,ddcInit
        cmp     ax,[di].ddc_iSysClr
        je      @F
        cCall   PropagateSysClrChange
@@:

        test    [si].ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jz      polyline_colors_good
        lea     bx,[si].ddc_la.la_ba
        call    MakeColorsValid
        mov     ax,0                              ;Error logged by MakeColorsValid
        js      pl_exit_relay
polyline_colors_good:

;/*
;**  check for a surface
;*/

        test    [si].ddc_fb,DDC_PRESENT
        jnz     ddc_all_set
        mov     ax,PMERR_BITMAP_NOT_SELECTED
pl_bad_exit_relay:
        jmp     pl_bad_exit
pl_exit_relay:
        jmp     pl_exit
ddc_all_set:

;/*
;**  make sure that the number is in bounds
;*/

        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        cmp     PolyN.hi,0
        jnz     pl_bad_exit_relay
        cmp     FunN.lo,off_PolyLine
        jz      @F

;/*
;**  DisjointLines takes only an even number of points.
;*/

        test    PolyN.lo,1
        jnz     pl_bad_exit_relay
@@:

;/*
;**  get a local copy of the style before we start batching
;** !!! we should really get local copies of all relevant DDC stuff right here !!!
;*/

        mov     ax,word ptr [si].ddc_la.la_bError ; AL=error, AH=mask position
        .errnz  la_bMask - la_bError - 1
        mov     wStylePosition,ax

;/*
;**  batch the points through the local buffer
;*/

        mov     ax,1
        mov     cx,PolyN.lo
        jcxz    pl_exit_relay
batchin_loop:                                     ; CX = count>0, SI = random
        cmp     cx,BATCH_POINTS
        jb      count_is_small
        mov     cx,BATCH_POINTS
count_is_small:
        sub     PolyN.lo,cx                       ; decrement count remaining
        mov     cLines,cx
        .errnz  size POINTL - 8
        shl     cx,2                              ; CX = word count
        lds     si,lpPolyXY
        assumes ds,nothing
        mov     ax,ss
        mov     es,ax                             ; ES = SS
        assumes es,nothing
        lea     di,aptl[SIZE POINTL]              ; skip first scratch point
        cld
        rep     movsw
        mov     lpPolyXY.lo,si                    ; advance pointer
        mov     ds,CodeData
        assumes ds,Data
        sub     di,SIZE POINTL                    ; DI = last point
        mov     si,hddc.lo                        ; SI = DDC


;/*
;**  deal with current positions
;*/

;/*
;**  overwrite first coordinate with physical current position
;*/

        CPUMode 386
        lgs     bx,[si].ddc_prddc                ; GS:BX = RDDC
        assumes gs,nothing
        rddc?   gs,bx
        mov     ax,gs:[bx].rddc_ptsCurPos.pts_x
        mov     aptl.ptl_x.lo,ax
        mov     ax,gs:[bx].rddc_ptsCurPos.pts_y
        mov     aptl.ptl_y.lo,ax

;/*
;**  transform the points in the buffer             
;*/

        test    seg_FunN,COM_TRANSFORM            ; FunN - MSW is commands
        jnz     points_are_world_coords

;/*
;**  transform new position to WORLD coordinates
;*/

        lea     bx,[bx].rddc_ptlWorldPos
        farPtr  lp_point,gs,bx
        CPUMode 286
        cCall   convert_screen_world,<lp_point,1> ; ds:si = ddc
        or      ax,ax
        jnz     short points_converted_to_screen
pl_exit_relay2:
        jmp     pl_exit

;/*
;**  transform all but the first point
;*/

points_are_world_coords:
        lea     dx,aptl[size POINTL]               ; don't transform first point!
        mov     cx,cLines
        farPtr  lp_point,ss,dx
        cCall   convert_world_screen,<lp_point,cx> ; DS:SI = ddc
        or      ax,ax
        jz      pl_exit_relay2
points_converted_to_screen:

;/*
;**  now that we know the new world coord current position
;**  won't overflow, set it.
;*/

        les     bx,lpPolyXY
        assumes es,nothing
        CPUMode 386
        mov     si,[si].ddc_prddc.off
        rddc?   gs,si
        sub     bx,SIZE POINTL
        mov     eax,es:[bx].ptl_x
        mov     gs:[si].rddc_ptlWorldPos.ptl_x,eax
        mov     eax,es:[bx].ptl_y
        mov     gs:[si].rddc_ptlWorldPos.ptl_y,eax

;/*
;**  save the new current position in SCREEN coordinates  
;*/

        mov     ax,ss:[di].ptl_x.lo
        mov     gs:[si].rddc_ptsCurPos.pts_x,ax
        mov     ax,ss:[di].ptl_y.lo
        mov     gs:[si].rddc_ptsCurPos.pts_y,ax

;/*
;**  calculate the bounding rectangle for the points
;*/

        lea     di,aptl
        mov     cx,cLines
        inc     cx
        cmp     FunN.lo,off_PolyLine
        jz      @F
        dec     cx                                ; DisjointLines: don't include
        add     di,SIZE POINTL                    ;   the current position.
@@:
        call    compute_bounds                    ; get inclusive bounds

;/*
;**  does it lie totally inside the clip rectangle?
;*/

        mov     rcsBounds.rcs_xLeft,ax
        mov     rcsBounds.rcs_yBottom,bx
        mov     rcsBounds.rcs_xRight,cx
        mov     rcsBounds.rcs_yTop,dx
        mov     di,PF_BETTER_CLIP
        rddc?   gs,si
        cmp     ax,gs:[si].rddc_arcsClip[0].rcs_xLeft
        jl      better_clip
        cmp     bx,gs:[si].rddc_arcsClip[0].rcs_yBottom
        jl      better_clip
        cmp     cx,gs:[si].rddc_arcsClip[0].rcs_xRight
        jge     better_clip
        cmp     dx,gs:[si].rddc_arcsClip[0].rcs_yTop
        jge     better_clip
        xor     di,di
better_clip:
        or      flags,di
        mov     si,gs:[si].rddc_npddc             ; SI = DDC

;/*
;**  add this in to the Bounds in the DDC if requested
;*/

        mov     di,FunN.hi                        ; DI = Command
        test    di,COM_BOUND+COM_ALT_BOUND
        jz      bounding_done
        call    InnerAccumulateBounds             ; DS:SI = DDC, DI = Command
        or      ax,ax
        jnz     bounding_done
pl_exit_relay3:
        jmp     pl_exit
bounding_done:

;/*
;**  do correlating
;*/

        mov     ax,1                              ; assume no correlation.
        test    di,COM_CORRELATE                  ; are we checking for correlation?
        jz      correlate_done                    ; jump if not.
        cmp     [si].ddc_crcsClip,0
        jz      correlate_done
        lea     ax,aptl
        cCall   <far ptr PolyLineCorrelate>,<ax,cLines,off_FunN>
        cmp     ax,2                              ; make sure we don't keep trying
        jnz     correlate_done                    ;  after we succeed

        inc     fHits                             ; set flag if coorelation
        and     FunN.hi,not COM_CORRELATE

correlate_done:

        mov     returnvalue,ax                    ; save return code.

;/*
;**  draw only if the COM_DRAW bit is on AND we're visible (not dead, IC, etc.)
;*/


        mov     cl,[si].ddc_fb
        and     cx,DDC_VISIBLE
;/*
;*/
        jz      batchin_next

        .errnz  COM_DRAW-DDC_VISIBLE

;/*
;**  if device, exclude cursor from intersection of clip and bounds
;*/

        test    [si].ddc_fb,DDC_DEVICE
        jz      dont_exclude
        lds     bx,[si].ddc_prddc                ; DS:BX = RDDC
        assumes ds,nothing
        mov     cx,[bx].rddc_arcsClip.rcs_xLeft
        mov     di,[bx].rddc_arcsClip.rcs_yBottom
        mov     dx,[bx].rddc_arcsClip.rcs_yTop
        dec     dx                                ; get inclusive
        mov     si,[bx].rddc_arcsClip.rcs_xRight
        dec     si                                ; get inclusive
        mov     bx,rcsBounds.rcs_xLeft
        cmp     cx,bx
        jg      @f
        mov     cx,bx                             ; CX = left (inclusive)
@@:     mov     bx,rcsBounds.rcs_yBottom
        cmp     di,bx
        jg      @f
        mov     di,bx                             ; DI = bottom (inclusive)
@@:     mov     bx,rcsBounds.rcs_xRight
        cmp     si,bx
        jl      @f
        mov     si,bx                             ; SI = right (inclusive)
@@:     mov     bx,rcsBounds.rcs_yTop
        cmp     dx,bx
        jl      @f
        mov     dx,bx                             ; DX = top (inclusive)
@@:     sub     dx,SCREEN_CY-1
        neg     dx                                ; DX = top (flipped inclusive)
        sub     di,SCREEN_CY-1
        neg     di                                ; DI = bottom (flipped inclusive)
        cmp     dx,di                             ; check for null
        jg      batchin_next
        cmp     cx,si
        jg      batchin_next
        call    far_exclude
        mov     ds,CodeData
        assumes ds,Data

dont_exclude:

;/*
;**  do_polylines needs to get the style position out of the DDC, so
;**  we'd better put it there!
;*/

        mov     di,hddc.lo                        ; DI = DDC for do_polylines
        mov     ax,wStylePosition
        mov     word ptr [di].ddc_la.la_bError,ax
        .errnz  la_bMask - la_bError - 1

;/*
;**  call do_polylines to actually pound the bits
;*/


        lea     ax,aptl
        mov     bx,FunN.hi
        cCall   far_do_polylines,<flags,cLines,ax,off_FunN,bx>
        assumes ds,nothing
        mov     wStylePosition,ax
batchin_next:
        mov     ax,returnvalue                    ; set return value.
        mov     cx,PolyN.lo
        jcxz    pl_exit
        jmp     batchin_loop

pl_bad_exit:
        save_error_code
        xor     ax,ax
pl_exit:
        cwd
        call    far_unexclude                      ; (I own the semaphore, don't I?)

        mov     ds,CodeData
        assumes ds,Data

;/*
;**  advance the style counter
;*/

        mov     di,hddc.lo
        mov     bx,wStylePosition
        mov     word ptr [di].ddc_la.la_bError,bx
        .errnz  la_bMask - la_bError - 1

;/*
;**  go home
;*/

        call    leave_driver
pl_exit_no_lock:
        cmp     ax,0
        je      pl_end
        cmp     fHits,0                                ; flag set if coorelation
        je      pl_end
        mov     ax,2
pl_end:
        fw_zero <es,cx>
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = ComputeBounds 
;*
;* DESCRIPTION   = Computes the inclusive bounding RECTS of an array of POINTLs.
;*
;*                 Registers Preserved:
;*                       SI,BP,DS,ES
;*                 Registers Destroyed:
;*                       DI
;*
;* INPUT         = SS:DI --> aptl
;*                 CX     =  Count of points
;* OUTPUT        = (EAX,EBX,ECX,EDX) = Bounding rect
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   compute_bounds,<PUBLIC,NEAR>,<si,bp>
cBegin

;/*
;**  initialize the rectangle to the first point
;*/

        mov     ax,ss:[di].ptl_x.lo              ; (AX,BX,BP,DX) = bounding rect
        mov     bx,ss:[di].ptl_y.lo
        mov     bp,ax
        mov     dx,bx
        dec     cx
        jz      compute_bounds_done
        add     di,SIZE POINTL

;/*
;**  loop through all other points
;*/

compute_bounds_loop:
        mov     si,ss:[di].ptl_x.lo
        cmp     ax,si
        jl      @F
        mov     ax,si
@@:     cmp     bp,si
        jg      @F
        mov     bp,si
@@:     mov     si,ss:[di].ptl_y.lo
        cmp     bx,si
        jl      @F
        mov     bx,si
@@:     cmp     dx,si
        jg      @F
        mov     dx,si
@@:     add     di,SIZE POINTL
        loop    compute_bounds_loop
compute_bounds_done:
        mov     cx,bp                             ; (AX,BX,CX,DX) = bounding rect
cEnd

sEnd    Code

sBegin  BlueMoon
        assumes cs,BlueMoon

;/***************************************************************************
;*
;* FUNCTION NAME = PolyLineCorrelate 
;*
;* DESCRIPTION   = Performs correlation on the given polyline.                     
;*
;* INPUT         = DS:SI = DDC
;*                 usFunN = ulFunN.lo of Gre function calling here.
;*                                                    
;*                 Registers Preserved:
;*                       DI,SI,BP,DS
;*                 Registers Destroyed:
;*                       BX,CX,DX,ES
;*
;*                 Calls:
;*                       clip_line
;*
;* OUTPUT        = NONE
;*                                                    
;* RETURN-NORMAL = AX = 1 if no correlation
;*                 AX = 2 if correlation
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

PLC_FIRST_PEL   equ     1

        assumes ds,Data
        assumes es,nothing

cProc   PolyLineCorrelate,<FAR,PUBLIC>,<si,di>
        parmW   npaptl                            ; on stack
        parmW   cLines
        parmW   usFunN
        localW  fsFlags
        localW  offNextLine
        localV  lsg,%(SIZE LINESEGMENT)
cBegin
        ddc?    si

;/*
;**  make sure the correlation rectangle is valid in the DDC
;*/

        test    [si].ddc_fb,DDC_CORR_INV
        jz      corr_is_valid
        call    far_recalc_correlate_rect
corr_is_valid:

        mov     fsFlags,0
        cmp     usFunN,off_PolyLine
        jnz     correlate_disjoint_lines

;/*
;**  copy the FIRST_PEL bit onto the stack
;*/

correlate_polylines:
        mov     offNextLine,SIZE POINTL
        test    [si].ddc_fb,DDC_FIRST_PEL
        jz      first_pel_and_count_set
        or      fsFlags,PLC_FIRST_PEL
        jmp     short first_pel_and_count_set

;/*
;**  We draw half as many lines as there are points for DisjointLines
;*/

correlate_disjoint_lines:
        add     npaptl,SIZE POINTL                ; Ignore current position
        mov     offNextLine,2 * SIZE POINTL
        shr     cLines,1

first_pel_and_count_set:

;/*
;**  compute the intersection of the clip rectangle with the pick window
;*/

        les     si,[si].ddc_prddc
        assumes es,nothing
        rddc?   es,si

        mov     ax,es:[si].rddc_arcsClip.rcs_xLeft
        mov     bx,es:[si].rddc_arcsClip.rcs_yBottom
        mov     cx,es:[si].rddc_arcsClip.rcs_xRight
        mov     dx,es:[si].rddc_arcsClip.rcs_yTop

        cmp     ax,es:[si].rddc_rcsCorr.rcs_xLeft
        jg      @F
        mov     ax,es:[si].rddc_rcsCorr.rcs_xLeft
@@:     cmp     bx,es:[si].rddc_rcsCorr.rcs_yBottom
        jg      @F
        mov     bx,es:[si].rddc_rcsCorr.rcs_yBottom
@@:     cmp     cx,es:[si].rddc_rcsCorr.rcs_xRight
        jl      @F
        mov     cx,es:[si].rddc_rcsCorr.rcs_xRight
@@:     cmp     dx,es:[si].rddc_rcsCorr.rcs_yTop
        jl      @F
        mov     dx,es:[si].rddc_rcsCorr.rcs_yTop
@@:

;/*
;**  send null intersections home
;*/

        cmp     ax,cx
        jge     no_correlation
        cmp     bx,dx
        jge     no_correlation

;/*
;**  stuff the test RECTS into the LINESEGMENT structure
;*/

        mov     lsg.lsg_rcsClip.rcs_xLeft,ax
        mov     lsg.lsg_rcsClip.rcs_yBottom,bx
        mov     lsg.lsg_rcsClip.rcs_xRight,cx
        mov     lsg.lsg_rcsClip.rcs_yTop,dx

;/*
;**  loop through all the lines
;*/

correlate_loop:
        mov     si,npaptl
        mov     bx,offNextLine                 ; offset (bytes) between start of two lines
        add     npaptl,bx
        mov     bx,ss:[si].ptl_x.lo            ; (BX,CX) = point 1
        mov     cx,ss:[si].ptl_y.lo
        mov     di,ss:[si][SIZE POINTL].ptl_x.lo ; (DI,SI) = point 2
        mov     si,ss:[si][SIZE POINTL].ptl_y.lo

;/*
;**  clip the line against the RECTS
;*/

        push    bp           
        lea     bp,lsg                            ; point to LINESEGMENT structure
        mov     dx,-1                             ; no POINTFX clipping!
        call    far_clip_line
        pop     bp

;/*
;**  correct for the first pel
;*/

        mov     dx,lsg.lsg_xA                     ; DX = xA
        mov     bx,lsg.lsg_xB                     ; BX = xB
        cmp     usFunN,off_PolyLine
        jnz     corrected_for_first_pel  ; DisjointLines always draws first pel
        test    fsFlags,PLC_FIRST_PEL
        jnz     corrected_for_first_pel
        or      di,di
        jz      correlate_next                    ; watch out for the zero length line!
        test    lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        jnz     is_left_exchanged
        cmp     dx,1
        adc     dx,0
        jmp     short corrected_for_first_pel
is_left_exchanged:
        dec     di
        cmp     di,bx
        sbb     bx,0
corrected_for_first_pel:
        and     fsFlags,not PLC_FIRST_PEL

;/*
;**  check for a hit
;*/

        mov     ax,2
        cmp     dx,bx
        jbe     PolyLineCorrelate_done

;/*
;**  go to the next line
;*/

correlate_next:
        dec     cLines
        jnz     correlate_loop

;/*
;**  return the result
;*/

no_correlation:
        mov     ax,1
PolyLineCorrelate_done:
        fw_zero <es>
cEnd

sEnd    BlueMoon

        end
