;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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/23/87                     Wesley O. Rupel [wesleyr] Optimized, Added
;*                                FireWalls, fixed comments, removed
;*                                pd_screen_sel
;*                                Wesley O. Rupel [wesleyr] Optimized, Added
;*                                FireWalls, fixed comments, removed
;*                                pd_screen_sel
;*   10/26/87                     Written by Kent Settle   (kentse)
;*                                Kent Settle [kentse] Changed to new
;*                                polyshortline format.
;*                                Kent Settle [kentse] Changed to new
;*                                polyshortline format.
;*   05/19/88                     Charles Whitmer [chuckwh] Rewrote from
;*                                scratch.  Now it always renders from left
;*                                to right, simplifying lots of logic and
;*                                eliminating several inner loops.
;*   06/20/88                     Bob Grudem [bobgru] Implemented the "max"
;*                                metric for line styling.
;*
;*****************************************************************************/

        .xlist
        include cmacros.inc
INCL_DDIPATHS           equ                      1
INCL_DDIMISC            equ                      1
INCL_GRE_LINES          equ                      1
INCL_DDICOMFLAGS        equ                      1
INCL_GPICORRELATION     equ                      1
INCL_GPIPRIMITIVES      equ                      1
        include pmgre.inc
DINCL_ROPS              equ     1
        include driver.inc
        include display.inc
        include njmp.mac
        include polyline.inc
        include assert.mac
        .list
;/*
;** This bit is the high bit of the style position in the shortline
;** structure.  We can use it because the style position keeps track
;** of a bit in a byte, so it only needs three bits (0-7).
;*/

PSL_YMAJOR      equ     8000h

        errcode <BITMAP_NOT_SELECTED>

        externA         SCREEN_CBSCAN
        externA         SCREEN_CY
        externA         DOSHUGEINCR

        externFP        FSRSemCheck

sBegin  Data
        externB         ddcInit
        externB         semDriver
sEnd    Data

        externFP        far_MakeColorsValid

sBegin  PtrCode
        externFP        far_exclude                     ; exclude area from screen
        externFP        far_unexclude                   ; clear excluded area
sEnd    PtrCode

sBegin  Code
        assumes cs,Code

        externW CodeData

        externNP        recalc_correlate_rect    ; MAJOR0B.ASM
        externNP        polyline_init             ; POLYLINE.ASM
        externNP        polyline_background_init
        externNP        PropagateSysClrChange
        externNP        ComputeShortlineBounds   ; Found in SLCORR.ASM
        externNP        ShortlineCorrelate       ; Found in SLCORR.ASM
;/***************************************************************************
;*
;* 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 = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        check   PolyShortLine,<hdc,psl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   PolyShortLine,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   psl
        parmD   hddc
        parmD   FunN
        include plylocal.inc
        localW  npfnRunHorz
        localW  npfnRunVert
        localW  npfnRunDiag
        localW  pRead
        localW  pReadStep
        localW  wDiagScanAdjust
        localV  rcsBounds,%(SIZE RECTS)
cBegin
        mov     Flags,0
        mov     returnvalue,1                     ; assume all OK
        mov     ds,CodeData
        assumes ds,Data

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

ifdef FIREWALLS
        cCall   FSRSemCheck,<DataOFFSET semDriver>
        or      ax,dx
        jz      @F
        rip     text,<PolyShortLine called without LockDevice>
@@:
endif

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

        mov     si,hddc.lo                        ; DS:SI --> DDC

        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      @F
        lea     bx,[si].ddc_la.la_ba
        call    far_MakeColorsValid
        js      shortline_error_exit              ; Error logged by MakeColorsValid
@@:

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

        test    [si].ddc_fb,DDC_PRESENT
        jnz     @F
        mov     ax,PMERR_BITMAP_NOT_SELECTED
        save_error_code
shortline_error_exit:
        xor     ax,ax                             ; indicate error
        jmp     shortline_exit
shortline_good_exit_relay:
        jmp     shortline_good_exit
@@:

;/*
;** compute bounds                                      
;*/

        cCall   ComputeShortlineBounds,<psl>
        mov     rcsBounds.rcs_xLeft,ax           ; save for use by exclude
        mov     rcsBounds.rcs_yBottom,bx
        mov     rcsBounds.rcs_xRight,cx ; these are inclusive!
        mov     rcsBounds.rcs_yTop,dx

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

        mov     di,FunN.hi                        ; DI = Command
ifdef FIREWALLS
        test    di,COM_BOUND+COM_ALT_BOUND
        jz      @F
        rip     text,<Bounds should not be set>
@@:
endif

;/*
;** compute correlation                                 
;*/

publab  sl_compute_corr

        test    di,COM_CORRELATE
        jz      correlate_done
        cCall   ShortlineCorrelate,<psl>; DS:SI = DDC
        mov     returnvalue,ax
correlate_done:

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

        mov     cl,[si].ddc_fb
        and     cl,DDC_VISIBLE
        .errnz  DDC_VISIBLE - COM_DRAW
        test    byte ptr FunN.hi,cl
        jz      shortline_good_exit_relay

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

        test    [si].ddc_fb,DDC_DEVICE
        jz      exclusion_done
        mov     dx,SCREEN_CY-1                    ; flip the vertical
        mov     di,dx
        mov     cx,rcsBounds.rcs_xLeft           ; CX = left
        sub     di,rcsBounds.rcs_yBottom; DI = bottom
        mov     si,rcsBounds.rcs_xRight ; SI = right inclusive
        sub     dx,rcsBounds.rcs_yTop            ; DX = top inclusive
        call    far_exclude
exclusion_done:

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

        mov     di,hddc.lo
        call    polyline_init

        assumes ds,nothing                        ; DS => surface

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

setup_shortline:

        cld
        mov     si,anpfnRunRoutines
        lods    word ptr cs:[si]
        mov     npfnRunHorz,ax
        lods    word ptr cs:[si]
        mov     npfnRunVert,ax
        lods    word ptr cs:[si]
        mov     npfnRunDiag,ax

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

        mov     wStyleStepDiag,0100h             ; special treatment for .._ALTERNATE
        cmp     LineStyle,LINETYPE_ALTERNATE - 1
        je      psl_styling_is_set_up
        mov     ax,wStyleStepHorz
        mov     wStyleStepHorzTmp,ax
        mov     ax,wStyleStepVert
        mov     wStyleStepVertTmp,ax
psl_styling_is_set_up:

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

        les     di,psl                            ; ES:DI = SHORTLINE
        assumes es,nothing

publab  shortlinesloop
shortlines_loop:

        cmp     LineStyle,LINETYPE_ALTERNATE - 1
        je      psl_have_style_steps

        mov     ax,wStyleStepHorzTmp             ;reset style step variables
        mov     bx,wStyleStepVertTmp

        test    es:[di].sl_slh.slh_usStyle,PSL_YMAJOR
        jnz     psl_y_major
        xor     bx,bx
        jmp     short psl_set_diag_style_step
psl_y_major:
        xor     ax,ax
psl_set_diag_style_step:

        mov     wStyleStepHorz,ax
        mov     wStyleStepVert,bx
        add     ax,bx
        mov     wStyleStepDiag,ax
psl_have_style_steps:


        mov     lsg.lsg_fsLineFlags,LF_Y_FLIP

        assert  es:[di].slh_usFormat,E,SLH_FORMAT_IS_16_DOT_16

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

        mov     bx,es:[di].slh_ptsStart.pts_y    ; BX = first Y
        mov     dx,es:[di].slh_ptsStop.pts_y
        mov     si,dx
        inc     si
        inc     bx                                ; allow a last Y of FFFF
        sub     si,bx
        njz     shortlines_next
        dec     bx
        sbb     cx,cx                             ; CX = FFFF if BX > DX
        xor     si,cx
        sub     si,cx                             ; SI = |DX - BX|
        mov     cSideSteps,si
        add     cx,cx
        inc     cx                                ; CX = sgn(DX - BX)
        sub     dx,cx                             ; move DX toward BX by one
        add     si,si                              ; DX = last Y
        add     si,di                             ; [SI].sl_ax => last point
        mov     cx,es:[si].sl_ax                 ; get the last point
        mov     ax,es:[si].sl_ax[-2]             ; get the second to last point
        inc     cx                                ; allow a last X of FFFF
        inc     ax
        cmp     ax,cx                             ; move the last point towards
        sbb     cx,0                              ;   the second to last point
        cmp     cx,ax
        adc     cx,-1                              ; CX = last X
        mov     ax,es:[di].slh_ptsStart.pts_x    ; AX = first X

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

        mov     pReadStep,2
        cmp     ax,cx
        jbe     @F
        xchg    ax,cx
        xchg    bx,dx
        mov     di,si
        mov     pReadStep,-2
        or      byte ptr lsg.lsg_fsLineFlags,LF_LEFT_XCHG
@@:     add     di,sl_ax                          ; DI is NOT the SHORTLINE anymore!
        mov     pRead,di
        mov     lsg.lsg_xStart,ax
        mov     lsg.lsg_yStart,bx

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

        mov     si,cbScanSize                     ; assume we're going down
        cmp     bx,dx
        jae     @F
        neg     si
        xor     byte ptr lsg.lsg_fsLineFlags,LF_Y_FLIP
@@:     mov     cbScanAddressDelta,si

;/*
;** do styling                                          
;*/

publab  sl_do_style

        cmp     LineStyle,LINETYPE_SOLID - 1
        jz      ignore_styles
        mov     di,psl.off
        sub     cx,ax                             ; CX = delta X
        mov     ax,cSideSteps
        dec     ax                                ; 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     LineStyle,LINETYPE_ALTERNATE - 1
        jnz     @F
        cmp     cx,ax                             ; set CF if AX > CX
        sbb     bx,bx                             ; BX = FFFF if AX > CX, else 0000
        and     ax,bx                             ; zero the smaller of AX or CX
        not     bx
        and     cx,bx
@@:

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

        mul     wStyleStepVert
        xchg    cx,ax
        mul     wStyleStepHorz
        add     ax,cx                             ; AX = style change
        mov     bx,es:[di].slh_usStyle           ; BX = style at start
        add     ax,bx                             ; AX = style at finish
        mov     dx,wStyleMask

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

        test    lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        jz      @F
        mov     bx,ax
        not     bx                                ; BX = style count to use
        mov     dl,dh                             ; DL = style mask to use
@@:     mov     bActiveStyleCounter,bl
        mov     cl,bh
        and     cl,7
        rol     dl,cl
        mov     bActiveStyleMask,dl
ignore_styles:

;/*
;** Compute the surface address.                        
;**                                                     
;** At some point in the code below each possible output media --  
;** color bitmap, mono bitmap, or color device  --  has a chance  
;** to initialize certain variables that depend on which of these it is. 
;** Most of these variables are used for "address" calculations in the 
;** actual drawing code.                                
;*/

publab  comp_surf_addr

;/*
;** currently DS is the first segment of the bitmap.
;*/

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

        mov     wDiagScanAdjust,0

        test    sd_flags,SD_DEVICE
        jz      not_device

;/*
;** DEVICE SHORT LINES
;**
;** We are doing ShortLines to the device.  It wants a separate X and Y
;** coordinate, not an address pointer (like DI) as the bitmaps require.
;** Thus the delta to the next scanline is simply 1 or -1.
;*/

        mov     wRotBitMask,bx                    ; BX == X coord (BitMask not needed)
        mov     pSurfaceAddress.off,dx           ; DX == scan line == device Y coord

        assert  si,E,cbScanAddressDelta
        or      si,si
        mov     si,1
        jns     @F
        neg     si
@@:
        mov     cbScanAddressDelta,si            ; set deltaY
        jmp     short   device_done
;/*
;**-------------------------
;*/

not_device:

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

        mov     cx,cScansPerSegment
        jcxz    not_huge_surface

        mov     si,pSurfaceStart.sel             ; SI = surface selector
        cmp     dx,cx
        jb      no_huge_adjust_needed
        mov     ax,dx
        xor     dx,dx
        div     cx                                ; ScanLine / cScansPerSegment
        assert  ah,E,0                            ; => DX = scan in final segment
        mov     ah,DOSHUGEINCR
        mul     ah
        add     si,ax
publab  no_huge_adj_needed
no_huge_adjust_needed:
        mov     pSurfaceAddress.sel,si
        mov     ds,si
        assumes ds,nothing

;/*
;** decide what the huge adjustments are
;*/
                                                  ; cScansPerSegment - ScanInFinalSegment
        sub     cx,dx                             ; => CX = number of remaining scans
        mov     ax,cbHugeScanWrap                ;  in this segment
        mov     si,DOSHUGEINCR
        test    lsg.lsg_fsLineFlags,LF_Y_FLIP
        jnz     @F
        mov     cx,dx
        inc     cx
        neg     ax
        neg     si
@@:     mov     selHugeDelta,si
        mov     cbHugeScanDelta,ax
not_huge_surface:
        mov     cScansLeftInSeg,cx

;/*
;** compute the offset (and bit mask in the MONO case)
;*/

        mov     ax,cbScanSize
        mul     dx                                ; ScanInFinalSegment * cbScanSize
        test    sd_flags,SD_COLOR
        jnz     packed_pixel_addressing

;/*
;** 8 pels per byte (MONO bitmap)
;*/

        mov     cx,bx                            ; BX = pixel in scan
        shr     bx,3
        add     ax,bx
        add     ax,pSurfaceStart.off             ; first byte of bitmap (after padding)
        mov     pSurfaceAddress.off,ax
        and     cl,7
        mov     al,80h
        ror     al,cl
        mov     bRotBitMask,al
        jmp     short   mono_bitmap_done

packed_pixel_addressing:

;/*
;** 1 pel per byte  (COLOR bitmap)
;*/

        add     ax,bx
        add     ax,pSurfaceStart.off             ; first byte of bitmap (after padding)
        mov     pSurfaceAddress.off,ax

;/*
;** bRotBitMask is not used for color bitmaps, but the code which
;** moves a pixel to the right in a mono bitmap will also happen
;** to work for color bitmaps iff this mask is all ones.
;*/

        mov     bRotBitMask,0FFh

;/*
;** The reason we don't use the bRotBitMask is that the address adjustment
;** to move to the next diagonal pel is very simple for packed pixel bitmaps.
;** The motion is done in one step using cbScanAddressDelta.
;** cbScanAddressDelta normally only handles deltaY motion.  We will
;** add wDiagScanAdjust to cbScanAddressDelta whenever we prepare to do
;** a diagonal run.  We will subtract it back off afterwards so it won't
;** adversly affect a subsequent vertical run.
;*/

        mov     wDiagScanAdjust,1

mono_bitmap_done:
device_done:

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

publab  run_shortline

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

        mov     di,pSurfaceAddress.off           ; DS:DI = surface address

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

do_a_run:
publab  do_a_run
        mov     si,pRead
        mov     bx,pReadStep
        mov     ax,es:[si]
        mov     cx,es:[si][bx]
        sub     cx,ax                             ; CX = number of pixels on this scan

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

        cmp     cx,1
        jb      run_vertical
        njz     run_diagonal
        add     si,bx
        mov     pRead,si
        mov     bx,wRotBitMask                    ; X coord if device, else BitMask
        call    npfnRunHorz

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

        dec     cSideSteps
        jz      done_with_shortline_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:
publab advance_diagonal
        cmp     LineStyle,LINETYPE_SOLID-1
        jz      diag_styling_done
        mov     cl,bActiveStyleCounter
        xor     ch,ch
        add     cx,wStyleStepDiag
        mov     bActiveStyleCounter,cl
        mov     cl,ch
        and     cl,7
        rol     bActiveStyleMask,cl
diag_styling_done:

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

        test    sd_flags,SD_DEVICE
        jnz     device_Xinc
        ror     bl,1
        adc     di,0
        db      3Ch                              ; cmp al,__  swallow the INC BX, avoid jmping
device_Xinc:
        inc     bx                               ; add 1 to device X coordinate
        mov     wRotBitMask,bx

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

advance_vertical_scan:
publab  advance_vertical_scan
        add     di,cbScanAddressDelta

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

        test    sd_flags,SD_DEVICE               ; device has no segment to be huge
        jnz     do_a_run
        dec     cScansLeftInSeg
        jnz     do_a_run
        mov     ax,cScansPerSegment              ; reset cScansLeftInSeg
        mov     cScansLeftInSeg,ax
        mov     ax,ds                             ; advance the segment
        add     ax,selHugeDelta
        mov     ds,ax
        assumes ds,nothing
        add     di,cbHugeScanDelta               ; wrap the surface address
        jmp     do_a_run

done_with_shortline_relay:
        jmp     done_with_shortline

;/*
;** 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     si,pRead
        mov     ax,es:[si]
        cmp     ax,es:[si][-2]
        jz      advance_vertical
        jmp     advance_diagonal

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

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

run_vertical:
publab  run_vertical
        add     si,bx                             ; SI = next scan
        inc     cx                                ; CX = count of vertical pels
        dec     cSideSteps
        jz      stop_vertical
        cmp     ax,es:[si][bx]                    ; AX = first X value
        jz      run_vertical
stop_vertical:
        mov     pRead,si

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

        mov     bx,wRotBitMask                    ; X coord if device, else BitMask
        call    npfnRunVert
        cmp     cSideSteps,0
        jz      done_with_shortline

;/*
;** 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     wRotBitMask,bx
        cmp     LineStyle,LINETYPE_SOLID-1
        jz      vert_styling_done
        mov     cl,bActiveStyleCounter
        xor     ch,ch
        add     cx,wStyleStepVert
        mov     bActiveStyleCounter,cl
        mov     cl,ch
        and     cl,7
        rol     bActiveStyleMask,cl
vert_styling_done:
        jmp     advance_vertical_scan

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

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

run_diagonal:
publab  run_diagonal
        xor     cx,cx
        inc     ax
run_diagonal_loop:
        add     si,bx                             ; SI = next scan
        inc     cx                                ; CX = count of diagonal pels
        inc     ax                                ; AX = expected X value
        dec     cSideSteps
        jz      stop_diagonal
        cmp     ax,es:[si][bx]
        jz      run_diagonal_loop
stop_diagonal:
        mov     pRead,si

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

        mov     ax,wDiagScanAdjust
        add     cbScanAddressDelta,ax
        mov     bx,wRotBitMask                    ; X coord if device, else BitMask
        call    npfnRunDiag
        mov     ax,wDiagScanAdjust
        sub     cbScanAddressDelta,ax
        cmp     cSideSteps,0
        jz      done_with_shortline

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

        test    byte ptr lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        njnz    advance_look_ahead
        jmp     advance_diagonal

done_with_shortline:
publab  done_with_shortline

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

shortlines_next:
        mov     di,psl.off
        mov     cx,es:[di].slh_pslhNext.sel
        jcxz    shortlines_loop_done
        mov     di,es:[di].slh_pslhNext.off
        mov     es,cx
        assumes es,nothing
        mov     psl.off,di
        jmp     shortlines_loop

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

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

shortlines_loop_done:
        call    npfnUnSetup
        call    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     LineStyle,LINETYPE_SOLID - 1
        jz      done_background
        mov     ds,CodeData
        assumes ds,Data
        mov     di,hddc.lo
        cmp     [di].ddc_la.la_ba.ba_bkmix,ROP_D    ; Leavealone
        je      done_background
        call    polyline_background_init
        assumes ds,nothing
        or      Flags,PF_DOING_BACKGROUND
        jmp     setup_shortline

done_background:

shortline_good_exit:
        mov     ax,returnvalue
shortline_exit:
        cwd
        fw_zero <es,cx>
cEnd

sEnd    Code

        end
