;*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     55,132
        TITLE    Major Functions
        SUBTITLE Header

;/*****************************************************************************
;*
;* SOURCE FILE NAME = MAJOR01.ASM
;*
;* DESCRIPTIVE NAME = Set and get attribute orders.
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/22/91
;*
;* 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
;*   11/22/91                     Written by Micrografx
;*   10/30/92  @50263      50263  Update style counter for clipped polylines
;*   11/26/92                     John Batty. Added DCAF changes.
;*   02/03/93              61415  Cliff Levesque no nee to limit # points to
;*                                < 65536.
;*
;*****************************************************************************/

        .386P
        .MODEL FLAT,SYSCALL

;/*
;** Included files
;*/

INCL_DDICOMFLAGS   EQU 1
INCL_GPIPRIMITIVES EQU 1
INCL_GRE_LINES     EQU 1
INCL_NOBASEAPI     EQU 1
;INCL_SAADEFS       EQU 1                                  ; @50263
OS2_NOPMAPI        EQU 1
        INCLUDE PMGRE.INC

DINCL_BITMAP       EQU 1
DINCL_ENABLE       EQU 1
        INCLUDE DRIVER.INC
        INCLUDE EXTERN.INC
        INCLUDE PROTOS.INC
        INCLUDE POLYLINE.INC

;/*
;** Equates
;*/

BATCH_POINTS EQU 100
        .ERRNZ  BATCH_POINTS AND 3

        .list                                              ; @50263

        .MODEL FLAT                                        ; @50263

        ASSUME  CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT            ; @50263

        .DATA                                              ; @50263

        PUBLIC  s_table                                    ; @50263
s_table     equ     this WORD
                                                           ; @50263
        db      10101010b, 01010101b    ; dotted line
        db      11001100b, 00110011b    ; short dash
        db      11100100b, 00100111b    ; dash dot
        db      10100000b, 00000101b    ; double dot
        db      11100111b, 11100111b    ; long dash
        db      11101010b, 01010111b    ; dash dot dot
        db      11111111b, 11111111b    ; solid
        db      00000000b, 00000000b    ; invisible
        db      10101010b, 01010101b    ; alternate dotted line

;*****************************************************
; Private functions
;*****************************************************

        .CODE

        SUBTITLE ComputeBounds
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = ComputeBounds
;*
;* DESCRIPTION   = Computes the inclusive bounding RECTS of an array of POINTLs.
;*
;* INPUT         = EDI --> aptl
;*                 ECX  =  Count of points
;* OUTPUT        = (EAX,EBX,ECX,EDX) = Bounding rect
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
ComputeBounds PROC SYSCALL PUBLIC USES esi ebp

;/*
;** Initialize the rectangle to the first point.
;*/

        MOV     EAX,[EDI].POINTL.ptl_x          ; (EAX,EBX,EBP,EDX) =
        MOV     EBX,[EDI].POINTL.ptl_y          ; bounding rect
        MOV     EBP,EAX
        MOV     EDX,EBX
        DEC     ECX
        JZ      ComputeBounds_done
        ADD     EDI,sizeof POINTL

;/*
;** Loop through all other points.
;*/

ComputeBounds_loop:
        MOV     ESI,[EDI].POINTL.ptl_x
        CMP     EAX,ESI
        JL      @F
        MOV     EAX,ESI
@@:
        CMP     EBP,ESI
        JG      @F
        MOV     EBP,ESI
@@:
        MOV     ESI,[EDI].POINTL.ptl_y
        CMP     EBX,ESI
        JL      @F
        MOV     EBX,ESI
@@:
        CMP     EDX,ESI
        JG      @F
        MOV     EDX,ESI
@@:
        ADD     EDI,sizeof POINTL
        LOOP    ComputeBounds_loop

ComputeBounds_done:
        MOV     ECX,EBP         ; (EAX,EBX,ECX,EDX) = Bounding rect
        RET

ComputeBounds ENDP

;/*
;** Public functions
;*/

        SUBTITLE GetCurrentPosition
        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         = C Prototype:
;*                   BOOL _syscall GetCurrentPosition (HDC     hdc,
;*                                                     PPOINTL pptPosition,
;*                                                     PVOID   pInstance,
;*                                                     ULONG   lFunction);
;*
;*                    where:
;*                      All arguments are as specified for the
;*                      GreGetCurrentPosition function.
;*
;* OUTPUT        = As specified for the GreGetCurrentPosition function.
;*
;* RETURN-NORMAL = EAX = 1
;* RETURN-ERROR  = EAX = 1
;*
;**************************************************************************/

ALIGN 4
GetCurrentPosition PROC SYSCALL PUBLIC uses EDI ESI EBX,
        hdc        :HDC,
        pptPosition:PPOINTL,
        pInstance  :PVOID,
        lFunction  :ULONG


        CLD
        MOV     ESI,pInstance           ; EDSI --> DDC
        MOV     EDX,ESI
        INVOKE  enter_driver
        JC      GCP_Exit_no_lock        ; EAX = 0 on error
        MOV     EDI,pptPosition         ; EDI = pptPosition
        MOV     ESI,[ESI].DDC.ddc_prddc ; ESI = RDDC
        rddc?   ESI
        TEST    lFunction,COM_TRANSFORM
        JZ      We_should_get_device_coordinates
        LEA     ESI,[ESI].RDDC.rddc_ptlWorldPos
        MOVSD
        MOVSD
        .ERRNZ  (sizeof POINTL)-8
        JMP     GetCurrentPosition_exit
ALIGN 4

We_should_get_device_coordinates:
        LEA     ESI,[ESI].RDDC.rddc_ptsCurPos.ptl_x
        MOVSD
        MOVSD

        .ERRNZ  RDDC.rddc_ptsCurPos.ptl_y - RDDC.rddc_ptsCurPos.ptl_x - 4
GetCurrentPosition_exit:

        MOV     EAX,1
        INVOKE  leave_driver

GCP_Exit_no_lock:
        fw_zero <ECX>

        DebugMsg <Leaving GetCurrentPosition>

        RET

GetCurrentPosition ENDP

        SUBTITLE SetCurrentPosition
        PAGE +

;/***************************************************************************
;*
;* 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         =
;*        C Prototype:
;*          BOOL _syscall SetCurrentPosition (HDC     hdc,
;*                                            PPOINTL pptPosition,
;*                                            PVOID   pInstance,
;*                                            ULONG   lFunction);
;*
;*           where:
;*             All arguments are as specified for the GreSetCurrentPosition function.
;*
;* OUTPUT        = As specified for the GreSetCurrentPosition function.
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

ALIGN 4
SetCurrentPosition PROC SYSCALL PUBLIC,
        hdc        :HDC,
        pptPosition:PPOINTL,
        pInstance  :PVOID,
        lFunction  :ULONG

        PUSH    EBX
        PUSH    EDI
        PUSH    ESI

;/*
;** Check if accumulation is set
;*/

        TEST    lFunction,COM_AREA + COM_PATH
        JZ      No_accum
        POP     ESI
        POP     EDI
        POP     EBX
        MOV     ESP,EBP
        POP     EBP
                                                ; Cleanframe
        JMP     pfnDefSetCurrentPosition
ALIGN 4

No_accum:
        CLD
        MOV     ESI,pInstance           ; ESI = DDC
        MOV     EDX,ESI
        INVOKE  enter_driver
        JC      SCP_Exit_no_lock        ; EAX = 0 on error
        MOV     EDI,pptPosition

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


        ASSUME ESI:PDDC

        OR      [ESI].ddc_fb,DDC_FIRST_PEL

;/*
;** Reset the line type sequence
;*/

        XOR     EAX,EAX
        MOV     WORD ptr [ESI].ddc_la.la_bError,AX
        .ERRNZ  LINE_ATTRS.la_bMask  - LINE_ATTRS.la_bError - 1
        .ERRNZ  LINE_ATTRS.la_bStepX - LINE_ATTRS.la_bMask  - 1

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

        TEST    lFunction,COM_TRANSFORM     ; lFunction - MSW is
                                                        ; commands
        JZ      Pt_is_screen


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

        PUSH    [EDI][4]
        PUSH    [EDI][0]
        .ERRNZ  sizeof POINTL - 8
        MOV     EBX,ESP
        INVOKE  convert_world_screen,ebx,1      ; ESI = DDC
        POP     EDX                     ; Checked by convert_world_screen
        POP     ECX                     ; Checked by convert_world_screen
        .ERRNZ  sizeof POINTL - 8
        OR      EAX,EAX                 ; Check return code from convert.
        JZ      SetCurrentPosition_exit ; Exit if error.

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

        MOV     ESI,[ESI].ddc_prddc             ; ESI = RDDC

        ASSUME ESI:PRDDC

        rddc?   ESI
        MOV     [ESI].rddc_ptsCurPos.ptl_x,EDX
        MOV     [ESI].rddc_ptsCurPos.ptl_y,ECX
        MOV     EDI,pptPosition

        ASSUME EDI:PPOINTL

        MOV     EBX,[EDI].ptl_y
        MOV     ECX,[EDI].ptl_x
        MOV     [ESI].rddc_ptlWorldPos.ptl_y,EBX
        MOV     [ESI].rddc_ptlWorldPos.ptl_x,ECX
        JMP     SetCurrentPosition_exit
ALIGN 4

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

Pt_is_screen:

        ASSUME ESI:PDDC

        MOV     EBX,[ESI].ddc_prddc             ; EBX = RDDC

        ASSUME EBX:PRDDC

        rddc?   EBX
        MOV     EAX,[EDI].ptl_y
        MOV     [EBX].rddc_ptsCurPos.ptl_y,EAX
        MOV     [EBX].rddc_ptlWorldPos.ptl_y,EAX
        MOV     EAX,[EDI].ptl_x
        MOV     [EBX].rddc_ptsCurPos.ptl_x,EAX
        MOV     [EBX].rddc_ptlWorldPos.ptl_x,EAX


        LEA     EBX,[EBX].rddc_ptlWorldPos
        INVOKE  convert_screen_world,EBX,1      ; ESI = DDC

SetCurrentPosition_exit:
        INVOKE  leave_driver

SCP_Exit_no_lock:
        fw_zero <ECX>
        POP     ESI
        POP     EDI
        POP     EBX

        DebugMsg <Leaving SetCurrentPosition>

        RET

        ASSUME EBX:NOTHING
        ASSUME ESI:NOTHING
        ASSUME EDI:NOTHING

SetCurrentPosition ENDP

        SUBTITLE DisjointLines
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = DisjointLines
;*
;* DESCRIPTION   = This function is invoked from the dispatch table in response to a
;*                 call to the GreDisjointLines function ad draws a sequence of
;*                 disjoint straight lines using the end-point pairs specified.
;*                 It is, actually, merely another entry point into the Polyline
;*                 function, which functions in a similar manner.  See below
;*                 for a more detailed explanation.
;*
;* INPUT         = C Prototype:
;*                   LONG _syscall DisjointLines (HDC     hdc,
;*                                                PPOINTL pptl,
;*                                                LONG    cPoints,
;*                                                PVOID   pInstance,
;*                                                ULONG   lFunction);
;*
;*                    where:
;*                      All parameters are as specified for the GreDisjointLines
;*                      function.
;*
;* OUTPUT        = As specified for the GreDisjointLines function.
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        OPTION  PROLOGUE:NONE
        OPTION  EPILOGUE:NONE

ALIGN 4
DisjointLines PROC SYSCALL PUBLIC,
                hdc                  :HDC,
                pptl                 :PPOINTL,
                CPoints              :LONG,
                pInstance            :PVOID,
                lFunction            :ULONG

DisjointLines ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        .ERRNZ  PolyLine-DisjointLines

        SUBTITLE PolyLine
        PAGE +

;/***************************************************************************
;*
;* 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
;*
;* INPUT         =  C Prototype:
;*                    LONG _syscall PolyLine (HDC     hdc,
;*                                            PPOINTL papPoint,
;*                                            LONG    CPoints,
;*                                            PVOID   pInstance,
;*                                            ULONG   lFunction);
;*
;*                     where:
;*                       All arguments are as specified for the GrePolyLine function.
;*
;*
;*
;* OUTPUT        = As specified for the GrePolyLine function.
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

ALIGN 4
PolyLine PROC SYSCALL PUBLIC USES edi esi ebx,
                hdc                  :HDC,
                papPoint             :PPOINTL,
                CPoints              :LONG,
                pInstance            :PVOID,
                lFunction            :ULONG

        LOCAL   aptl [BATCH_POINTS+1]:POINTL
        LOCAL   rcsBounds            :OurRECTS
        LOCAL   lReturnValue         :DWORD
        LOCAL   flags                :DWORD
        LOCAL   cLines               :DWORD
        LOCAL   ptlPoint             :POINTL
        LOCAL   wStylePosition       :WORD

        LOCAL   LineStyle            :DWORD                ; @50263
        LOCAL   dwStyleStepHorz      :DWORD                ; @50263
        LOCAL   dwStyleStepVert      :DWORD                ; @50263
        LOCAL   dwStyleCounter       :DWORD                ; @50263
        LOCAL   Points               :DWORD                ; @50263
        LOCAL   offNextLine          :DWORD                ; @50263
        LOCAL   Count                :DWORD                ; @50263

ifdef  JTUNE        ;IBMJ
 or swFlags,SW_CT_DIS_REQ  ; redraw CELL if use it
endif ;JTUNE        ;IBMJ

;/*
;** Send to Engine if accumulating.
;*/

        TEST    lFunction,(COM_AREA+COM_PATH)
        JNZ     Polylines_to_simulation

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

        MOV     ESI,pInstance           ; ESI --> DDC
        MOV     EDX,ESI                 ; EDX --> DDC
        ENTER_DRIVER2
        JC      PL_Exit_no_lock         ; EAX = 0 on error

        CMP     [ESI].DDC.ddc_crcsClip,2        ; Only valid inside semaphore!
        JAE     Leave_and_simulate              ; Continue if less than 2 clip rects
        CMP     [ESI].DDC.ddc_la.la_sWidth,1    ; Send back cosmetic wideline to engine
        JLE     Polyline_we_can_do

Leave_and_simulate:
        INVOKE  leave_driver

;/*
;** Bop off to the simulation
;*/

Polylines_to_simulation:
        CMP     WORD ptr lFunction,NGrePolyLine
        JNZ     @F
        pop     ebx
        pop     esi
        pop     edi
        LEAVE
        JMP     pfnDefPolyLine          ; Pass it back to the engine
ALIGN 4

@@:
        pop     ebx
        pop     esi
        pop     edi
        LEAVE
        JMP     pfnDefDisjointLines     ; Pass it back to the engine
ALIGN 4

;/*
;** We will draw it!
;*/

Polyline_we_can_do:
        MOV     flags,0
        MOV     EAX,[ESI].DDC.ddc_iSysClr   ; EAX = Index of current sys colors
        LEA     EDI,ddcInit

        CMP     EAX,[EDI].DDC.ddc_iSysClr   ; Instance colors same as sys colors?
        JE      @F                      ;  Y - Continue
        INVOKE  PropagateSysClrChange   ;  N - Change them

@@:
                                        ; Foreground and backgound colors
                                        ; valid?
        TEST    [ESI].DDC.ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        JZ      Polyline_colors_good    ;  Y - Continue
        LEA     EBX,[ESI].DDC.ddc_la.la_ba  ;  N - Make them so
        INVOKE  MakeColorsValid
        MOV     EAX,0                   ; Error logged by MakeColorsValid
        JS      PL_Exit

Polyline_colors_good:

;/*
;** Check for a surface
;*/

        TEST    [ESI].DDC.ddc_fb,DDC_PRESENT
        JNZ     DDC_All_set
        MOV     EAX,PMERR_BITMAP_NOT_SELECTED

DDC_All_set:

;/*
;** Make sure that the number is in bounds.
;*/

;        MOV     EAX,PMERR_INV_LENGTH_OR_COUNT                    61415
;        CMP     WORD ptr CPoints+2,0                             61415
;        JNZ     PL_Bad_exit                                      61415
        CMP     WORD ptr lFunction,NGrePolyLine
        JZ      @F

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

        TEST    CPoints,1
        JNZ     PL_Bad_exit

@@:

;/*
;** 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 [ESI].DDC.ddc_la.la_bError  ; AL=error,
                                                        ; AH=mask position
        .ERRNZ  LINE_ATTRS.la_bMask-LINE_ATTRS.la_bError-1
        MOV     wStylePosition,AX

;/*
;** Batch the points through the local buffer.
;*/

        MOV     EAX,1
        MOV     ECX,CPoints
        JECXZ   PL_Exit_Relay
Batchin_loop:                           ; ECX = count > 0, ESI = Random

        CMP     ECX,BATCH_POINTS        ; Make sure that the loop count is no
        JB      Count_is_small          ; greater than the number of points
        MOV     ECX,BATCH_POINTS        ; that can be held in local storage at
                                        ; one time.

Count_is_small:
        SUB     CPoints,ECX             ; Decrement count remaining
        MOV     cLines,ECX
        .ERRNZ  sizeof POINTL - 8
        SHL     ECX,1                   ; ECX = DWORD count
        MOV     ESI,papPoint

;/*
;** Can go outside loop
;*/

        LEA     EDI,aptl[SIZE POINTL]   ; Skip first scratch point
        CLD
    REP MOVSD
        MOV     papPoint,ESI            ; Advance pointer
        SUB     EDI,sizeof POINTL       ; EDI --> Last point
        MOV     ESI,pInstance           ; ESI --> DDC

;/*
;** Deal with current positions.
;*/

;/*
;** Overwrite first coordinate with physical current position.
;*/

        MOV     EBX,[ESI].DDC.ddc_prddc ; EBX = RDDC
        rddc?   EBX
        MOV     EAX,[EBX].RDDC.rddc_ptsCurPos.ptl_x
        MOV     aptl.ptl_x,EAX
        MOV     EAX,[EBX].RDDC.rddc_ptsCurPos.ptl_y
        MOV     aptl.ptl_y,EAX

;/*
;** Transform the points in the buffer.
;*/

        TEST    lFunction,COM_TRANSFORM ; MSW is commands
        JNZ     Points_are_world_coords

;/*
;** Transform new position to WORLD coordinates.
;*/

        LEA     EBX,[EBX].RDDC.rddc_ptlWorldPos
        INVOKE  convert_screen_world,EBX,1              ; ESI = DDC
        OR      EAX,EAX
        JNZ     Points_converted_to_screen

PL_Exit_Relay:
        JMP     PL_Exit
ALIGN 4

;/*
;** Transform all but the first point.
;*/

Points_are_world_coords:
        LEA     EDX,aptl[size POINTL]           ; don't xform first point!
        MOV     ECX,cLines
        INVOKE  convert_world_screen,EDX,ECX    ; ESI = DDC
        OR      EAX,EAX
        JZ      PL_Exit

Points_converted_to_screen:

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

        MOV     EBX,papPoint
        MOV     ESI,[ESI].DDC.ddc_prddc
        rddc?   ESI
        SUB     EBX,sizeof POINTL
        test    lFunction,COM_TRANSFORM
        jnz     @F
        mov     eax,[ebx].POINTL.ptl_x
        mov     ptlPoint.ptl_x,eax
        mov     eax,[ebx].POINTL.ptl_y
        mov     ptlPoint.ptl_y,eax
        mov     esi,[esi].RDDC.rddc_npddc
        INVOKE  convert_screen_world, ADDR ptlPoint, 1
        lea     ebx,ptlPoint
        mov     esi,[esi].DDC.ddc_prddc
@@:
        MOV     EAX,[EBX].POINTL.ptl_x
        MOV     [ESI].RDDC.rddc_ptlWorldPos.ptl_x,EAX
        MOV     EAX,[EBX].POINTL.ptl_y
        MOV     [ESI].RDDC.rddc_ptlWorldPos.ptl_y,EAX

;/*
;** Save the new current position in SCREEN coordinates.
;*/

        MOV     EAX,[EDI].POINTL.ptl_x
        MOV     [ESI].RDDC.rddc_ptsCurPos.ptl_x,EAX
        MOV     EAX,[EDI].POINTL.ptl_y
        MOV     [ESI].RDDC.rddc_ptsCurPos.ptl_y,EAX

;/*
;** Calculate the bounding rectangle for the points.
;*/
        LEA     EDI,aptl
        MOV     ECX,cLines
        INC     ECX
        CMP     WORD ptr lFunction,NGrePolyLine
        JZ      @F
        DEC     ECX                     ; DisjointLines: don't include
        ADD     EDI,sizeof POINTL       ; the current position.

@@:
        INVOKE  ComputeBounds           ; Get inclusive bounds

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

        MOV     rcsBounds.rcs_xLeft,EAX
        MOV     rcsBounds.rcs_yBottom,EBX
        MOV     rcsBounds.rcs_xRight,ECX
        MOV     rcsBounds.rcs_yTop,EDX


        MOV     EDI,PF_BETTER_CLIP
        rddc?   ESI
        CMP     EAX,[ESI].RDDC.rddc_arcsClip[0].rcl_xLeft
        JL      Better_clip
        CMP     EBX,[ESI].RDDC.rddc_arcsClip[0].rcl_yBottom
        JL      Better_clip
        CMP     ECX,[ESI].RDDC.rddc_arcsClip[0].rcl_xRight
        JGE     Better_clip
        CMP     EDX,[ESI].RDDC.rddc_arcsClip[0].rcl_yTop
        JGE     Better_clip
        XOR     EDI,EDI

Better_clip:
        OR      flags,EDI
        MOV     ESI,[ESI].RDDC.rddc_npddc               ; ESI --> DDC

;/*
;** Add this in to the Bounds in the DDC if requested.
;*/

        MOV     eDI,lFunction           ; DI = Command
ifdef DCAF                                                           ;          
;/*
;** We must pass all types of bounds accumulation to the             ;          
;** accumulation function.                                           ;          
;*/
        test    eDI,COM_BOUND+COM_ALT_BOUND+COM_SCR_BOUND            ;          
else  ; DCAF                                                         ;          
        TEST    eDI,COM_BOUND+COM_ALT_BOUND
endif ; DCAF                                                         ;          
        JZ      Bounding_done
        INVOKE  InnerAccumulateBounds           ; ESI --> DDC, DI = Command
        OR      EAX,EAX
        JNZ     Bounding_done

PL_Exit3:
        JMP     PL_Exit
ALIGN 4

Bounding_done:

;/*
;** Do correlating
;*/

        MOV     EAX,1                   ; Assume no correlation.
        TEST    eDI,COM_CORRELATE       ; Are we checking for correlation?
        JZ      Correlate_done          ; Jump if not
        CMP     [ESI].DDC.ddc_crcsClip,0
        JZ      Correlate_done
        INVOKE  PolyLineCorrelate,addr aptl,cLines,lFunction

        CMP     EAX,2                   ; Make sure we don't keep trying
        JNZ     Correlate_done          ; after we succeed

        AND     lFunction,not COM_CORRELATE

Correlate_done:
        MOV     lReturnValue,EAX        ; Save return code.

;/*
;** Draw only if the COM_DRAW bit is on AND we're visible (not dead, IC, etc.)
;** Send everybody into the drawing code anyway
;** We must hit FIRST_PEL and styling updates
;*/

        MOV     CL,[ESI].DDC.ddc_fb
        AND     CX,DDC_VISIBLE

;/*
;** The following line was taken out to fix PTR #PSM04063.  We still check for
;** the COM_DRAW bit, but we do it later in the code (in far_do_polylines) so
;** that we are sure to update the FIRST_PEL and styling info. (PRK) 5/25/91                                             00677 00675
;*/

        JZ      Batchin_next
        .ERRNZ  COM_DRAW SHR 16 - DDC_VISIBLE

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

        TEST    [ESI].DDC.ddc_fb,DDC_DEVICE
        JZ      Dont_exclude
        MOV     EBX,[ESI].DDC.ddc_prddc                 ; EBX --> RDDC
        MOV     ECX,[EBX].RDDC.rddc_arcsClip.rcl_xLeft
        MOV     EDI,[EBX].RDDC.rddc_arcsClip.rcl_yBottom
        MOV     EDX,[EBX].RDDC.rddc_arcsClip.rcl_yTop
        DEC     EDX                                     ; Get inclusive
        MOV     ESI,[EBX].RDDC.rddc_arcsClip.rcl_xRight
        DEC     ESI                                     ; Get inclusive
        MOV     EBX,rcsBounds.rcs_xLeft
        CMP     ECX,EBX
        JG      @f
        MOV     ECX,EBX                         ; ECX = left (inclusive)
@@:
        MOV     EBX,rcsBounds.rcs_yBottom
        CMP     EDI,EBX
        JG      @f
        MOV     EDI,EBX                         ; EDI = bottom (inclusive)
@@:
        MOV     EBX,rcsBounds.rcs_xRight
        CMP     ESI,EBX
        JL      @f
        MOV     ESI,EBX                         ; ESI = right (inclusive)
@@:
        MOV     EBX,rcsBounds.rcs_yTop
        CMP     EDX,EBX
        JL      @f
        MOV     EDX,EBX                         ; EDX = top (inclusive)
@@:
        SUB     EDX,SCREEN_CY           ;SEL 1-29-92
        INC     EDX                     ;SEL 1-29-92
        NEG     EDX                     ; EDX = top (flipped inclusive)
        SUB     EDI,SCREEN_CY           ;SEL 1-29-92
        INC     EDI                     ;SEL 1-29-92
        NEG     EDI                     ; EDI = bottom (flipped inclusive)
        CMP     EDX,EDI                 ; Check for null
;       JG      Batchin_next                               ; @50263
        JG      UpdateStylePosInBatch
        CMP     ECX,ESI
;       JG      Batchin_next                               ; @50263
        JG      UpdateStylePosInBatch
        INVOKE  far_exclude

Dont_exclude:

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

        MOV     EDI,pInstance           ; EDI --> DDC for do_polylines
        MOV     AX,wStylePosition
        MOV     WORD ptr [EDI].DDC.ddc_la.la_bError,AX
        .ERRNZ  LINE_ATTRS.la_bMask - LINE_ATTRS.la_bError - 1

;/*
;** Call do_polylines to actually pound the bits.
;** Pulling this in line would allow us to clean up lots of
;** copying (like we're doing with the style).
;*/

        LEA     EAX,aptl
ifndef IBMJ        ;IBMJ
        INVOKE  do_polylines,flags,cLines,EAX,WORD ptr lFunction, WORD PTR lFunction[2]
else  ;IBMJ        ;IBMJ
 INVOKE do_polylines,ADDR rcsBounds,flags,cLines,EAX,WORD ptr lFunction, WORD PTR lFunction[2]
endif ;IBMJ        ;IBMJ
        MOV     wStylePosition,AX
        JMP     Batchin_next                               ; @50263

;/*
;** The following code is added to fix 50263
;**
;** UpdateStylePosInBatch:
;**
;**   - get the line style of the batch
;**   - if line style == LINETYPE_SOLID, get the next batch
;**     else if line style == LINETYPE_ALTERNATE, set style ratio
;**     else get step style ratio (X step, Y step)
;**   - if X step != Y step
;**        for each line in the batch
;**            Xinc = X step * delta X
;**            Yinc = Y step * delta Y
;**            if Yinc < Xinc
;**               wStylePosition += Xinc
;**            else
;**               wStylePosition += Yinc
;**     else
;**        for each line in the batch
;**            if delta Y < delta X
;**               wStylePosition += X step * delta X
;**            else
;**               wStylePosition += Y step * delta Y
;**
;*/

UpdateStylePosInBatch:                                     ; @50263

        mov     eax,cLines
        mov     Count,eax
        lea     eax,aptl
        mov     Points,eax
        cmp     WORD ptr lFunction,NGrePolyLine
        jnz     setup_disjointlines
        mov     offNextLine,SIZE POINTL
        jmp     @f

setup_disjointlines:
        add     Points,SIZE POINTL               ; Ignore current position
        mov     offNextLine,2 * SIZE POINTL
        shr     Count,1                          ; Count = cPoints / 2
@@:
        MOV     EDI,pInstance                    ; EDI --> DDC
        mov     ebx,[edi].DDC.ddc_la.la_usType       ; get line style
        mov     BYTE PTR LineStyle,bl
        cmp     BL,LINETYPE_SOLID                ; ignore if solid type
        jz      Batchin_next
        cmp     BL,LINETYPE_ALTERNATE
        jz      @f
        add     ebx,ebx
        movzx   eax,s_table[ebx]             ; get style mask from the table
        mov     ax,WORD PTR [edi].DDC.ddc_la.la_bStepX  ; AL=step x,AH=step y
        .errnz  LINE_ATTRS.la_bStepY - LINE_ATTRS.la_bStepX - 1
        xor     ebx,ebx
        xchg    bl,ah                            ; AX = X step, BX = Y step
        mov     dwStyleStepHorz,eax              ; get style ratio
        mov     dwStyleStepVert,ebx
        jmp     loop_thru_polylines
@@:
        mov     eax,100h                         ; set the same step style ratio
        mov     dwStyleStepHorz,eax
        mov     dwStyleStepVert,eax

loop_thru_polylines:

        mov     esi,Points
        mov     ebx,offNextLine         ; offset (bytes) between start of 2 lines
        add     Points,ebx

        ASSUME  esi:PTR POINTL

        mov     ebx,[esi].ptl_x                 ; (BX,CX) = point 1
        mov     ecx,[esi].ptl_y
        mov     edi,[esi][SIZE POINTL].ptl_x    ; (DI,SI) = point 2
        mov     esi,[esi][SIZE POINTL].ptl_y

        cmp     ebx,edi
        jle     left_to_right                    ; if x_start < x_end
        xchg    ebx,edi

left_to_right:
        cmp     ecx,esi
        jle     bottom_to_top                    ; if y_start < y_end
        xchg    ecx,esi

bottom_to_top:
        sub     edi,ebx                          ; delta X
        sub     esi,ecx                          ; delta Y

        mov     eax,dwStyleStepHorz
        mov     ebx,dwStyleStepVert

        cmp     eax,ebx
        jz      same_XYstep
        mul     edi                              ; eax = X step * delta X
        xchg    eax,ebx
        mul     esi                              ; eax = Y step * delta Y
        cmp     eax,ebx
        jge     @f
        mov     ax,wStylePosition
@@:
        mov     bx,wStylePosition
        add     ax,bx
        mov     wStylePosition,ax
        jmp     next_line_in_batch

same_XYstep:
        cmp     esi,edi                          ; edi = delta X, esi = delta Y
        jge     @f                               ; if delta Y >= delta X
        mul     edi                              ; eax = X step * delta X
        jmp     inc_style_pos
@@:
        mul     esi                              ; eax = Y step * delta Y

inc_style_pos:
        mov     bx,wStylePosition
        add     ax,bx
        mov     wStylePosition,ax

next_line_in_batch:
        dec     Count
        jnz     loop_thru_polylines

Batchin_next:
        MOV     EAX,lReturnValue        ; Set return value.
        MOV     ECX,CPoints
        JECXZ   PL_Exit
        JMP     Batchin_loop
ALIGN 4

PL_Bad_exit:
        save_error_code
        XOR     EAX,EAX

PL_Exit:
        INVOKE  far_unexclude           ; (I own the semaphore, don't I?)

;/*
;** Advance the style counter.
;*/

        MOV     EDI,pInstance
        MOV     BX,wStylePosition
        MOV     WORD ptr [EDI].DDC.ddc_la.la_bError,BX
        .ERRNZ  LINE_ATTRS.la_bMask - LINE_ATTRS.la_bError - 1

;/*
;** Go home.
;*/

        INVOKE  leave_driver

PL_Exit_no_lock:
        fw_zero <ECX>

        ASSUME ESI:NOTHING                                 ; @50263

        RET

PolyLine ENDP

PLC_FIRST_PEL EQU 1

        SUBTITLE PolyLineCorrelate
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = PolyLineCorrelate
;*
;* DESCRIPTION   =  Performs correlation on the given polyline.
;*
;* INPUT         = C Prototype:
;*                   ULONG _syscall PolyLineCorrelate (PPOINTL paptl,
;*                                                     ULONG   cLines,
;*                                                     ULONG   lFunction);
;*                 where:
;*                   paptl     --> End point of line.
;*                   cLines     =  Count of lines.
;*                   lFunction  =  Function.
;*
;*                   NOTE:
;*                     ESI --> DDC
;*
;*                 Registers Preserved:
;*                       DI,SI,BP,DS
;*                 Registers Destroyed:
;*                       BX,CX,DX,ES
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 1 if no correlation
;*                 2 if correlation
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
PolyLineCorrelate PROC SYSCALL PUBLIC USES esi edi,
                paptl      :PPOINTL,
                cLines     :ULONG,
                lFunction  :DWORD

        LOCAL   offNextLine:DWORD
        LOCAL   lsg        :LINESEGMENT
        LOCAL   fsFlags    :WORD

        ddc?    ESI

;/*
;** Make sure the correlation rectangle is valid in the DDC.
;*/

        TEST    [ESI].DDC.ddc_fb,DDC_CORR_INV
        JZ      Corr_is_valid
        INVOKE  recalc_correlate_rect

Corr_is_valid:
        MOV     fsFlags,0
        CMP     WORD ptr lFunction,NGrePolyLine
        JNZ     Correlate_disjoint_lines

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

Correlate_polylines:
        MOV     offNextLine,sizeof POINTL
        TEST    [ESI].DDC.ddc_fb,DDC_FIRST_PEL
        JZ      First_pel_and_count_set
        OR      fsFlags,PLC_FIRST_PEL
        JMP     First_pel_and_count_set
ALIGN 4

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

Correlate_disjoint_lines:
        ADD     paptl,sizeof POINTL             ; Ignore current position
        MOV     offNextLine,2 * sizeof POINTL
        SHR     cLines,1

First_pel_and_count_set:

;/*
;** Compute the intersection of the clip rectangle with the pick window.
;*/

        MOV     ESI,[ESI].DDC.ddc_prddc
        rddc?   ESI
        MOV     EAX,[ESI].RDDC.rddc_arcsClip.rcl_xLeft
        MOV     EBX,[ESI].RDDC.rddc_arcsClip.rcl_yBottom
        MOV     ECX,[ESI].RDDC.rddc_arcsClip.rcl_xRight
        MOV     EDX,[ESI].RDDC.rddc_arcsClip.rcl_yTop
        CMP     EAX,[ESI].RDDC.rddc_rcsCorr.rcl_xLeft
        JG      @F
        MOV     EAX,[ESI].RDDC.rddc_rcsCorr.rcl_xLeft
@@:
        CMP     EBX,[ESI].RDDC.rddc_rcsCorr.rcl_yBottom
        JG      @F
        MOV     EBX,[ESI].RDDC.rddc_rcsCorr.rcl_yBottom
@@:
        CMP     ECX,[ESI].RDDC.rddc_rcsCorr.rcl_xRight
        JL      @F
        MOV     ECX,[ESI].RDDC.rddc_rcsCorr.rcl_xRight
@@:
        CMP     EDX,[ESI].RDDC.rddc_rcsCorr.rcl_yTop
        JL      @F
        MOV     EDX,[ESI].RDDC.rddc_rcsCorr.rcl_yTop

@@:

;/*
;** Send null intersections home.
;*/

        CMP     EAX,ECX
        JGE     No_correlation
        CMP     EBX,EDX
        JGE     No_correlation

;/*
;** Stuff the test RECTS into the LINESEGMENT structure.
;*/

        MOV     lsg.lsg_rcsClip.rcl_xLeft,EAX
        MOV     lsg.lsg_rcsClip.rcl_yBottom,EBX
        MOV     lsg.lsg_rcsClip.rcl_xRight,ECX
        MOV     lsg.lsg_rcsClip.rcl_yTop,EDX

;/*
;** Loop through all the lines
;*/

Correlate_loop:
        MOV     ESI,paptl
        MOV     EBX,offNextLine ; Offset (bytes) between start of two lines
        ADD     paptl,EBX
        MOV     EBX,[ESI].POINTL.ptl_x                  ; (EBX,ECX) = Point 1
        MOV     ECX,[ESI].POINTL.ptl_y
        MOV     EDI,[ESI][sizeof POINTL].POINTL.ptl_x   ; (EDI,ESI) = Point 2
        MOV     ESI,[ESI][sizeof POINTL].POINTL.ptl_y

;/*
;** Clip the line against the RECTS.
;*/

        PUSH    EBP     
        LEA     EBP,lsg ; point to LINESEGMENT structure
        MOV     EDX,-1  ; no POINTFX clipping!
        INVOKE  far_clip_line
        POP     EBP

;/*
;** Correct for the first pel.
;*/

        MOV     EDX,lsg.lsg_xA                  ; EDX = xA
        MOV     EBX,lsg.lsg_xB                  ; EBX = xB
        CMP     WORD ptr lFunction,NGrePolyLine
        JNZ     Corrected_for_first_pel         ; DisjointLines always draws
                                                ; first pel
        TEST    fsFlags,PLC_FIRST_PEL
        JNZ     Corrected_for_first_pel
        OR      EDI,EDI
        JZ      Correlate_next                  ; Watch out for the zero
                                                ; length line!
        TEST    lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        JNZ     Is_left_exchanged
        CMP     EDX,1
        ADC     EDX,0
        JMP     Corrected_for_first_pel
ALIGN 4

Is_left_exchanged:
        DEC     EDI
        CMP     EDI,EBX
        SBB     EBX,0

Corrected_for_first_pel:
        AND     fsFlags,not PLC_FIRST_PEL

;/*
;** Check for a hit.
;*/

        MOV     EAX,2
        CMP     EDX,EBX
        JBE     PolyLineCorrelate_done

;/*
;** Go to the next line.
;*/

Correlate_next:
        DEC     cLines
        JNZ     Correlate_loop

;/*
;** Return the result.
;*/

No_correlation:
        MOV     EAX,1

PolyLineCorrelate_done:

        RET

PolyLineCorrelate ENDP

        END
