;*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 = SHORTLN.ASM
;*
;* DESCRIPTIVE NAME = The PolyShortLine routines.
;*
;*
;* VERSION      V2.0
;*
;* DATE         10/26/87
;*
;* DESCRIPTION  The PolyShortLine routines.
;*
;*
;* FUNCTIONS    PolyShortLine
;*
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   10/26/87                     Written by Kent Settle   (kentse)
;*   10/23/87                     Wesley O. Rupel [wesleyr] Optimized, Added
;*                                FireWalls, fixed comments, removed
;*                                pd_screen_sel
;*   10/26/87                     Kent Settle [kentse] Changed to new
;*                                polyshortline format.
;*   11/26/92                     John Batty. Added DCAF changes.
;*
;*****************************************************************************/

        .386

        OPTION  OLDSTRUCTS

        .xlist

INCL_DDIPATHS           equ    1
INCL_DDIMISC            equ    1
INCL_GRE_LINES          equ    1
INCL_DDICOMFLAGS        equ    1
INCL_GPICORRELATION     equ    1
INCL_GPIERRORS          equ    1
INCL_GPIPRIMITIVES      equ    1
DINCL_ENABLE            equ    1
DINCL_BITMAP            equ    1

        include pmgre.inc

DINCL_ROPS              equ    1

        include driver.inc
        include display.inc
        include egafam.inc
        include polyline.inc
        include assert.mac
        include extern.inc
        include protos.inc
if SCAN_CNT EQ 768
        include oem_macs.inc
PF_DEST_IS_DEV  EQU             8
endif

        .list

        .MODEL FLAT

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

        .DATA

        .CODE


;/***************************************************************************
;*
;* FUNCTION NAME = PolyShortLine
;*
;* DESCRIPTION   =
;*
;*    PolyShortLine initializes things for the polyshortline 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 the destination
;*    device.  When all of the necessary initialization is complete, we jump
;*    to polyshortline_loop which does the line drawing.
;*
;*    This function draws a series of short lines.  This function is not
;*    available at the API.
;*
;*    The parameters include a pointer to the short line structure given below,
;*    which is a linked list of short lines.  The function should render each
;*    shortline in the list until a null sl_next is found.
;*
;*    The current position is not affected by this call.  The lines are
;*    assumed to be already clipped.
;*
;*    lpScan_links is a pointer to the first short_line structure, of the
;*    following format:
;*
;*    SHORTLINEHEADER struc
;*       slh_usStyle     dw  ?
;*       slh_usFormat      dw  ?
;*       slh_ptsStart    dw  (size POINTS)/2 dup (?)
;*       slh_ptsStop     dw  (size POINTS)/2 dup (?)
;*       slh_sxLeft      dw  ?
;*       slh_sxRight     dw  ?
;*       slh_pslhNext    dd  ?
;*       slh_pslhPrev    dd  ?
;*    SHORTLINEHEADER ends
;*       Short Line
;*    SHORTLINE struc
;*       sl_slh          dw  (size SHORTLINEHEADER)/2 dup (?)
;*       sl_ax           dw  1 dup (?)
;*    SHORTLINE ends
;*
;*    The structure is a discrete representation of a curve.  A curve starts
;*    at point X0,Y0 and ends at point X1,Y1.  For each of the Y1 - Y0 + 1
;*    rows there is exactly one X value, contained in the X array.  The steps
;*    are stored in absolute coordinates.
;*
;*    Example:
;*
;*          4|
;*          3|                                         X
;*          2|              X X X X X
;*          1|      X X X X
;*          0|X X X
;*            0 1 2 3 4 5 6 7 8 9 10111213
;*
;*          If this short line was defined from left to right, then
;*                  xstart = 0, ystart = 0
;*                  xstop = 13, ystop = 4
;*                  the array of X values is 0,3,7,12,13
;*
;*          If this short line was defined from right to left, then
;*                  xstart = 12, ystart = 3
;*                  xstop = -1, ystop = -1
;*                  the array of X values is 12,11,6,2,-1
;*
;*          NOTE: there are Y1 - Y0 + 1 numbers in the X array.
;*          NOTE: the last point, (xstop,ystop), is not drawn.
;*
;*    It should also be noted that the shortline must be monotonic in both
;*    X and Y.
;*
;*
;*
;*
;*
;* INPUT         =
;*
;*
;*
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

PolyShortLine   PROC SYSCALL USES esi edi EBX,      hdc:DWORD, psl:DWORD,
                                                hddc:DWORD, FunN:DWORD
  LOCAL   returnvalue:DWORD,
          dwStyleCounter:DWORD,
          Flags:DWORD,
          Count:DWORD,
          Points:DWORD
  LOCAL   npddc:DWORD,
          dwStyleMask:DWORD,
          npfnUnSetup:DWORD,
          CurLineColor:DWORD,
          DrawModeIndex:DWORD,
          cPlanes:DWORD
  LOCAL   cbNextPlane:DWORD,
          dwBitmapROP:DWORD,
          dwStyleStepHorz:DWORD,
          dwStyleStepVert:DWORD,
          dwStyleStepDiag:DWORD
  LOCAL   dwStyleStepHorzTmp:DWORD,
          dwStyleStepVertTmp:DWORD,
          offNextLine:DWORD,
          cbScanSize:DWORD,
          cbHugeScanWrap:DWORD,
          cySurface:DWORD
  LOCAL   cScansPerSegment:DWORD,
          pSurfaceStart:DWORD,
          anpfnRunRoutines:DWORD,
          LineStyle:DWORD,
          npfnPassSetup:DWORD,
          cPasses:DWORD,
          lsg:LINESEGMENT
  LOCAL   dwStyleStepRun:DWORD,
          dwStyleStepSide:DWORD,
          dwActiveStyleCounter:DWORD,
          dwActiveStyleMask:DWORD,
          yA:DWORD,
          cScans:DWORD,
          cA:DWORD,
          cB:DWORD,
          cm:DWORD
  LOCAL   npfnRunRoutine:DWORD,
          iWhichDDA:DWORD,
          dwError:DWORD,
          dwFracS:DWORD,
          dwRotBitMask:DWORD,
          cbScanAddressDelta:DWORD,
          cbSideStepAddressDelta:DWORD,
          cbHugeScanDelta:DWORD,
          selHugeDelta:DWORD,
          dwScan:DWORD
  LOCAL   pSurfaceAddress:DWORD,
          cTmpScans:DWORD,
          dwTmpError:DWORD,
          dwTmpScan:DWORD,
          dwTmpRotBitMask:DWORD,
          dwTmpActiveStyleCounter:DWORD,
          dwTmpActiveStyleMask:DWORD,
          cTmpPasses:DWORD,
          TmpCurLineColor:DWORD
  LOCAL   npfnRunHorz:DWORD,
          npfnRunVert:DWORD,
          npfnRunDiag:DWORD,
          pRead:DWORD,
          pTmpRead:DWORD,
          pReadStep:DWORD,
          rclBounds:RECTL
if SCAN_CNT EQ 768
                        LOCAL   start_bank:DWORD
endif


        DebugMsg <PolyShortLine, DISPATCH, shortln, CLIFFL>
ifdef FIREWALLS
        int 3
endif

        mov     Flags,0
        mov     returnvalue,1                     ; assume all OK

;/*
;** This call only makes sense with the device locked, check it out!
;*/

ifdef FIREWALLS2

        INVOKE  FSRSemCheck,OFFSET semDriver
        or      eax,edx
        jz      @F

        rip     text,<PolyShortLine called without LockDevice>
@@:

endif
        INSURE_VISREGIONNOTIFY

;/*
;** make the colors valid
;*/

        mov     esi,hddc                          ; DS:SI --> DDC

        ASSUME  esi:PTR DDC, edi:PTR DDC

        mov     eax,[esi].ddc_iSysClr
        lea     edi,ddcInit
        cmp     eax,[edi].ddc_iSysClr
        je      @F
        INVOKE  PropagateSysClrChange
@@:

        test    [esi].ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jz      @F
        lea     ebx,[esi].ddc_la.la_ba
        INVOKE  MakeColorsValid
        js      shortline_error_exit              ; Error logged by MakeColorsValid
@@:

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

        test    [esi].ddc_fb,DDC_PRESENT
        jnz     @F
        mov     eax,PMERR_BITMAP_NOT_SELECTED

        save_error_code

shortline_error_exit:

        xor     eax,eax                           ; indicate error
        jmp     shortline_exit

shortline_good_exit_relay:

        jmp     shortline_good_exit
@@:

;/*
;** compute bounds
;*/

        INVOKE  ComputeShortlineBounds, psl

        mov     rclBounds.rcl_xLeft,eax          ; save for use by exclude
        mov     rclBounds.rcl_yBottom,ebx
        mov     rclBounds.rcl_xRight,ecx ; these are inclusive!
        mov     rclBounds.rcl_yTop,edx

;/*
;** accumulate them if requested
;*/

        mov     edi,FunN                          ; DI = Command

ifdef FIREWALLS

        test    edi,COM_BOUND+COM_ALT_BOUND
        jz      @F

        rip     text,<Bounds should not be set>
@@:

endif

ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** Although there is no need to do the GPI or USER bounds for       ;          
;** this primitive (because this can only be called as a result      ;          
;** of a engine simulation which is responsible for accumulating     ;          
;** the bounds anyway), we must always do SCREEN bounds.             ;          
;*/                                                                  ;          
        test    edi,COM_SCR_BOUND                                    ;          
        jz      bounds_considered                                    ;          
                                                                     ;          
;/*                                                                  ;          
;** The bounding rectangle is currently in (eax,ebx),(ecx,edx)       ;          
;** This may be a NULL rectangle, in which case we should not        ;          
;** accumulate it.                                                   ;          
;** A NULL rectangle will have badly ordered coords (ie eax > ecx,   ;          
;** ebx > edx), when considering the values as positive values       ;          
;** (since this primitive deals only in SCREEN coords).              ;          
;** Typically the NULL rectangle we would have here is               ;          
;** (FFFF,FFFF), (0,0).                                              ;          
;*/                                                                  ;          
        cmp     eax,ecx                                              ;          
        ja      bounds_considered                                    ;          
        cmp     ebx,edx                                              ;          
        ja      bounds_considered                                    ;          
                                                                     ;          
        call    InnerAccumulateBounds   ; esi->DDC, edi = Command    ;          
                                                                     ;          
bounds_considered:                                                   ;          
endif ; DCAF                                                         ;          

;/*
;** compute correlation
;*/

        test    edi,COM_CORRELATE
        jz      correlate_done

        INVOKE  ShortlineCorrelate, psl        ; DS:SI = DDC

        mov     returnvalue,eax

correlate_done:

;/*
;** draw the lines
;*/

        mov     cl,[esi].ddc_fb
        and     cl,DDC_VISIBLE

        .errnz  DDC_VISIBLE - COM_DRAW SHR 16

        test    byte ptr FunN[2],cl
        jz      shortline_good_exit_relay

;/*
;** exclude the pointer if the device
;*/

        test    [esi].ddc_fb,DDC_DEVICE
        jz      exclusion_done
        mov     edx,SCREEN_CY    ;SEL 1-29-92
        DEC     EDX              ;SEL 1-29-92   ; flip the vertical
        mov     edi,edx
        mov     ecx,rclBounds.rcl_xLeft         ; CX = left
        sub     edi,rclBounds.rcl_yBottom       ; DI = bottom
        mov     esi,rclBounds.rcl_xRight        ; SI = right inclusive
        sub     edx,rclBounds.rcl_yTop          ; DX = top inclusive

        INVOKE  far_exclude

exclusion_done:

;/*
;** initialize according to the physical device type
;*/

        mov     edi,hddc
        call    polyline_init

;/*
;** Determine the Run Routines.
;*/

setup_shortline:

        cld
        mov     esi,anpfnRunRoutines
        lodsd
        mov     npfnRunHorz,eax
        lodsd
        mov     npfnRunVert,eax
        lodsd
        mov     npfnRunDiag,eax

;/*
;** Initialize style variables used in the loop.
;*/

        mov     dwStyleStepDiag,0100h            ; special treatment for .._ALTERNATE
        cmp     BYTE PTR LineStyle,LINETYPE_ALTERNATE - 1
        je      psl_styling_is_set_up
        mov     eax,dwStyleStepHorz
        mov     dwStyleStepHorzTmp,eax
        mov     eax,dwStyleStepVert
        mov     dwStyleStepVertTmp,eax

psl_styling_is_set_up:

;/*
;** Loop through all shortlines.
;*/

        mov     edi,psl                           ; ES:DI = SHORTLINE

        ASSUME  edi:PTR SHORTLINE

shortlines_loop:

        cmp     BYTE PTR LineStyle,LINETYPE_ALTERNATE - 1
        je      psl_have_style_steps

        mov     eax,dwStyleStepHorzTmp           ;reset style step variables
        mov     ebx,dwStyleStepVertTmp

        test    [edi].sl_slh.slh_ulStyle,PSL_YMAJOR
        jnz     psl_y_major
        xor     ebx,ebx
        jmp     psl_set_diag_style_step

psl_y_major:

        xor     eax,eax

psl_set_diag_style_step:

        mov     dwStyleStepHorz,eax
        mov     dwStyleStepVert,ebx
        add     eax,ebx
        mov     dwStyleStepDiag,eax

psl_have_style_steps:


        mov     lsg.lsg_fsLineFlags,LF_Y_FLIP

        assert  [edi].sl_slh.slh_ulFormat,E,SLH_FORMAT_IS_16_DOT_16

;/*
;** put the shortline endpoints into (AX,BX) - (CX,DX)
;*/

        mov     ebx,[edi].sl_slh.slh_ptlStart.ptl_y ; BX = first Y
        mov     edx,[edi].sl_slh.slh_ptlStop.ptl_y
        mov     esi,edx
        inc     esi
        inc     ebx                               ; allow a last Y of FFFF
        sub     esi,ebx
        jz      shortlines_next
        dec     ebx
        sbb     ecx,ecx                           ; CX = FFFF if BX > DX
        xor     esi,ecx
        sub     esi,ecx                           ; SI = |DX - BX|
        mov     cScans,esi
        add     ecx,ecx
        inc     ecx                               ; CX = sgn(DX - BX)
        sub     edx,ecx                           ; move DX toward BX by one
        add     esi,esi                            ; DX = last Y
        add     esi,edi                           ; [SI].sl_ax => last point

        ASSUME  esi:PTR SHORTLINE
;/*
;**!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;**
;** CARFUL
;**
;**!!!!!!!!!!!!!!!!!!!!!!
;*/

        mov     ecx,[esi].sl_ax        ; get the last point
        mov     eax,[esi].sl_ax[-4]              ; get the second to last point
        inc     ecx                               ; allow a last X of FFFF
        inc     eax
        cmp     eax,ecx                           ; move the last point towards
        sbb     ecx,0                             ;   the second to last point
        cmp     ecx,eax
        adc     ecx,-1                             ; CX = last X
        mov     eax,[edi].sl_slh.slh_ptlStart.ptl_x ; AX = first X

;/*
;** reverse the right to left case
;*/

        mov     pReadStep,4
        cmp     eax,ecx
        jbe     @F
        xchg    eax,ecx
        xchg    ebx,edx
        mov     edi,esi
        mov     pReadStep,-4
        or      BYTE PTR lsg.lsg_fsLineFlags,LF_LEFT_XCHG
@@:     add     edi,OFFSET SHORTLINE.sl_ax        ; DI is NOT the SHORTLINE anymore!
        mov     pRead,edi
        mov     lsg.lsg_xStart,eax
        mov     lsg.lsg_yStart,ebx

;/*
;** set the surface scan address delta
;*/

        mov     esi,cbScanSize                    ; assume we're going down
        cmp     ebx,edx
        jae     @F
        neg     esi
        xor     BYTE PTR lsg.lsg_fsLineFlags,LF_Y_FLIP
@@:     mov     cbScanAddressDelta,esi

;/*
;** do styling
;*/

        cmp     BYTE PTR LineStyle,LINETYPE_SOLID - 1
        jz      ignore_styles
        mov     edi,psl
        sub     ecx,eax                           ; CX = delta X
        mov     eax,cScans
        dec     eax                               ; AX = delta Y
;/*
;** count only the major direction for LINETYPE_ALTERNATE
;**!!! I assume octant carving so that there is a major direction. !!!
;**!!! Otherwise, we would need to walk the shortline.   !!!
;*/

        cmp     BYTE PTR LineStyle,LINETYPE_ALTERNATE - 1
        jnz     @F
        cmp     ecx,eax                           ; set CF if AX > CX
        sbb     ebx,ebx                           ; BX = FFFF if AX > CX, else 0000
        and     eax,ebx                           ; zero the smaller of AX or CX
        not     ebx
        and     ecx,ebx
@@:

;/*
;** compute the style advance
;*/

        mul     dwStyleStepVert
        xchg    ecx,eax
        mul     dwStyleStepHorz
        add     eax,ecx                           ; AX = style change
        mov     ebx,[edi].sl_slh.slh_ulStyle     ; BX = style at start
        add     eax,ebx                           ; AX = style at finish
        mov     edx,dwStyleMask

;/*
;** reverse the style if we've exchanged left for right
;*/

        test    lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        jz      @F
        mov     ebx,eax
        not     ebx                               ; BX = style count to use
        mov     dl,dh                             ; DL = style mask to use
@@:     mov     BYTE PTR dwActiveStyleCounter,bl
        mov     cl,bh
        and     cl,7
        rol     dl,cl
        mov     BYTE PTR dwActiveStyleMask,dl

ignore_styles:

;/*
;** Compute the surface address.
;*/

        mov     ebx,lsg.lsg_xStart                ; BX = pixel in scan
        mov     eax,lsg.lsg_yStart
        mov     edx,cySurface                     ; surface top is at low addresses
        dec     edx                               ;  => invert y coordinate
        sub     edx,eax                           ; DX = scan line

;/*
;** handle adjustment of huge surfaces
;*/

if SCAN_CNT EQ 768

;/*
;**Start Bank Stuff-------
;*/
        mov     ecx,0
        test    Flags,PF_DEST_IS_DEV
        jz      not_huge_surface

        mov     ecx,SCREEN_LPB

        push    eax
        push    edx
        mov     edx,0
        mov     start_bank,edx
        SetBankRW
        pop     edx
        pop     eax

        mov     esi,pSurfaceStart                ; SI = surface selector
        cmp     edx,ecx
        jb      no_huge_adjust_needed
        mov     eax,edx
        xor     edx,edx
        div     ecx                               ; DX = scan in final segment

        push    eax
        push    edx
        mov     edx,eax
        mov     start_bank,edx
        SetBankRW
        pop     edx
        pop     eax

;/*
;**End   Bank Stuff-------
;*/

else ;768
        mov     ecx,cScansPerSegment
        jecxz   not_huge_surface
        mov     esi,pSurfaceStart                ; SI = surface selector
endif ;768

no_huge_adjust_needed:

        mov     pSurfaceAddress,esi

;/*
;** decide what the huge adjustments are
;*/

        sub     ecx,edx                           ; CX = number of remaining scans
if SCAN_CNT EQ 768
        mov     eax,0
        mov     esi,1
else
        mov     eax,cbHugeScanWrap               ;  in this segment

endif
        test    lsg.lsg_fsLineFlags,LF_Y_FLIP
        jnz     @F
        mov     ecx,edx
        inc     ecx
        neg     eax
        neg     esi
@@:     mov     selHugeDelta,esi
        mov     cbHugeScanDelta,eax

not_huge_surface:

        mov     dwScan,ecx                        ; number of remaining scans

;/*
;** compute the offset and bit mask
;*/

        mov     eax,cbScanSize
        mul     edx
        shl     ebx,16                        ; discard the high word, use only the
        rol     ebx,16                        ; low word for calculating the offset
        mov     ecx,ebx
        shr     ebx,3
        add     eax,ebx
        add     eax,pSurfaceStart
        mov     pSurfaceAddress,eax
        and     cl,7
        mov     al,80h
        ror     al,cl
        mov     BYTE PTR dwRotBitMask,al

;/*
;** Setup for a pass.
;*/

;/*
;** copy all the variables that the DDA loop will destroy
;*/

        mov     eax,cPasses
        mov     cTmpPasses,eax
        mov     al,BYTE PTR CurLineColor
        mov     BYTE PTR TmpCurLineColor,al

do_another_pass:

        mov     eax,pRead
        mov     pTmpRead,eax
        mov     bl,BYTE PTR dwRotBitMask
        mov     BYTE PTR dwTmpRotBitMask,bl

;/*
;** load the surface address (we assume the segment is loaded)
;*/

        mov     edi,pSurfaceAddress              ; DS:DI = surface address

;/*
;** call the per pass setup routine
;*/

        call    npfnPassSetup                     ; DX = EGA port
        or      eax,eax
        jz      do_next_pass

;/*
;** Run the SHORTLINE!
;*/

;/*
;** read the data from the short line structure
;*/

do_a_run:

        mov     esi,pTmpRead
        mov     ebx,pReadStep
        mov     eax,DWORD PTR [esi]
        mov     ecx,DWORD PTR [esi][ebx]
        sub     ecx,eax                           ; CX = number of pixels on this scan

;/*
;** handle the horizontal case
;*/

        cmp     cx,1
        jb      run_vertical
        jz      run_diagonal
        add     esi,ebx
        mov     pTmpRead,esi
        mov     bl,BYTE PTR dwTmpRotBitMask
        call    npfnRunHorz

;/*
;** see if we're done
;*/

        dec     cScans
        jz      do_next_pass_relay

;/*
;** do look-ahead if going in reverse
;*/

        test    BYTE PTR lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        jnz     advance_look_ahead

;/*
;** advance the style along the diagonal
;*/

advance_diagonal:

        cmp     BYTE PTR LineStyle,LINETYPE_SOLID-1
        jz      diag_styling_done
        mov     cl,BYTE PTR dwActiveStyleCounter
        movzx   ecx,cl
        add     ecx,dwStyleStepDiag
        mov     BYTE PTR dwActiveStyleCounter,cl
        mov     cl,ch
        and     cl,7
        rol     BYTE PTR dwActiveStyleMask,cl

diag_styling_done:

;/*
;** move a pixel to the right
;*/

        ror     bl,1
        adc     edi,0
        mov     BYTE PTR dwTmpRotBitMask,bl

;/*
;** do a vertical move
;*/

advance_vertical_scan:

        add     edi,cbScanAddressDelta

;/*
;** do a huge vertical step, if needed
;*/

        dec     dwScan
        jnz     do_a_run
        mov     eax,cScansPerSegment             ; reset dwScan
        mov     dwScan,eax
        add     edi,cbHugeScanDelta              ; wrap the surface address
        jmp     do_a_run

do_next_pass_relay:

        jmp     do_next_pass

;/*
;** handle reverse look-ahead
;*/

;/*
;** The theory here is that if we are reading the SHORTLINE backwards, we
;** don't know whether to do a vertical or diagonal step after a run.  So
;** we check the next delta, 0 => vertical, otherwise diagonal.
;*/

advance_look_ahead:

        mov     esi,pTmpRead
        mov     eax,DWORD PTR [esi]
        cmp     eax,DWORD PTR [esi][-4]
        jz      advance_vertical
        jmp     advance_diagonal

;/*
;** handle the vertical case
;*/


;/*
;** figure out how far we can go
;*/

run_vertical:

        add     esi,ebx                           ; SI = next scan
        inc     ecx                               ; CX = count of vertical pels
        dec     cScans
        jz      stop_vertical
        cmp     eax,DWORD PTR [esi][ebx]          ; AX = first X value
        jz      run_vertical

stop_vertical:

        mov     pTmpRead,esi

;/*
;** draw the vertical pels
;*/

        mov     bl,BYTE PTR dwTmpRotBitMask
        call    npfnRunVert
        cmp     cScans,0
        jz      do_next_pass

;/*
;** do look-ahead if going in reverse
;*/

        test    BYTE PTR lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        jnz     advance_look_ahead

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

advance_vertical:

        mov     BYTE PTR dwTmpRotBitMask,bl
        cmp     BYTE PTR LineStyle,LINETYPE_SOLID-1
        jz      vert_styling_done
        mov     cl,BYTE PTR dwActiveStyleCounter
        movzx   ecx,cl
        add     ecx,dwStyleStepVert
        mov     BYTE PTR dwActiveStyleCounter,cl
        mov     cl,ch
        and     cl,7
        rol     BYTE PTR dwActiveStyleMask,cl

vert_styling_done:

        jmp     advance_vertical_scan

;/*
;** handle the diagonal case
;*/


;/*
;** figure out how far we can go
;*/

run_diagonal:

        xor     ecx,ecx
        inc     eax

run_diagonal_loop:

        add     esi,ebx                           ; SI = next scan
        inc     ecx                               ; CX = count of diagonal pels
        inc     eax                               ; AX = expected X value
        dec     cScans
        jz      stop_diagonal
        cmp     eax,DWORD PTR [esi][ebx]
        jz      run_diagonal_loop

stop_diagonal:

        mov     pTmpRead,esi

;/*
;** draw the diagonal pels
;*/

        mov     bl,BYTE PTR dwTmpRotBitMask
        call    npfnRunDiag
        cmp     cScans,0
        jz      do_next_pass

;/*
;** do look-ahead if going in reverse
;*/

        test    BYTE PTR lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        jnz     advance_look_ahead
        jmp     advance_diagonal

;/*
;** see if we need another pass
;*/

do_next_pass:

        dec     cTmpPasses
        jnz     do_another_pass

;/*
;** do the next SHORTLINE
;*/

shortlines_next:

        mov     edi,psl
        mov     ecx,[edi].sl_slh.slh_pslhNext
        jecxz   shortlines_loop_done
        mov     edi,[edi].sl_slh.slh_pslhNext
        mov     psl,edi
        jmp     shortlines_loop

;/*
;** clean up and go home
;*/


;/*
;** restore any hardware defaults
;*/

shortlines_loop_done:

        call    npfnUnSetup

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

;/*
;** If the shortline is not solid and the background mix mode is not
;** transparent, then go back and draw the background line, unless we
;** have already.
;*/

        test    Flags,PF_DOING_BACKGROUND
        jnz     done_background
        cmp     BYTE PTR LineStyle,LINETYPE_SOLID - 1
        jz      done_background
        mov     edi,hddc

        ASSUME edi:PTR DDC

        cmp     [edi].ddc_la.la_ba.ba_bkmix,ROP_D    ; Leavealone
        je      done_background
        call    polyline_background_init
        or      Flags,PF_DOING_BACKGROUND
        jmp     setup_shortline

done_background:

shortline_good_exit:

        mov     eax,returnvalue

shortline_exit:

        fw_zero <ecx>

                RET

PolyShortLine   ENDP

        end
