;*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 = pldda.asm
;*
;* DESCRIPTIVE NAME = Polyline drawing device driver, subroutine to run  
;*                    line DDAs.                                         
;*
;*
;* VERSION      V2.0
;*
;* DATE         
;*
;* DESCRIPTION  
;*              
;*    This file contains the "workhorse routine" which determines the
;*    DDA to use for a particular line, and computes the DDA parameters.
;*   
;*    These routines are called from POLYLINE.ASM (PolyLines) and
;*    SHORTLN.ASM (PolyShortLine -- thru which all arcs are drawn)
;*   
;*    Given a set of points, draw a set of polylines connecting adjoining
;*    points.  Depending on whether we are writing to the Display or a bitmap
;*    we initialize as necessary.  Solid and styled lines are handled.
;*    Small (<= 64k bytes) monochrome and color bitmaps and huge monochrome
;*    and color bitmaps are all supported.  A run length slice algorithm is
;*    used to determine the pixels used to draw each line.  The algorithm is
;*    explained later on.  
;*   
;*    This code is written for a device which can draw solid lines to the
;*    display in hardware.  Lines to bitmaps are drawn in software.
;*   
;*    There are sixteen raster operations (sets of logical operations) performed
;*    on the data written out.  We assume the hardware handles all this for us
;*    in a single pass.  Bitmaps are also handled in a single pass because
;*    they are stored in packed-pixel, rather than planar, format.
;*   
;*    Lines are drawn from left to right.  So if a line moves from right
;*    to left, the endpoints are swapped and the line is drawn from left to
;*    right.
;*
;* FUNCTIONS    setup_poly_frame_dda
;*              polyline_workhorse_routine,
;*                                         
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   02/23/87                     Kent Settle [kentse] Major re-write.
;*   04/08/87                     Kent Settle [kentse] Modified to draw all
;*                                lines moving right.
;*   04/30/87                     Kent Settle [kentse] Added huge bitmap
;*                                handling.
;*   06/06/87                     Author: Wes Rupel   (wesleyr)
;*   05/08/88                     Charles Whitmer [chuckwh] Rewrote from
;*                                scratch.  Clipping is vastly simplified.
;*   05/20/88                     Charles Whitmer [chuckwh] Derived all the
;*                                above for the case of clipped lines, which
;*                                Bresenham neglected to cover in his paper.
;*   06/11/88                     Wes Rupel [wesleyr] EGA --> 8-bit color/packed
;*                                pixel ==> Massive Changes.
;*   06/20/88                     Bob Grudem [bobgru] Implemented the "max"
;*                                metric for line styling.
;*   09/16/88                     Bob Grudem [bobgru] Placed in separate module
;*                                in an attempt to ease maintenance across the
;*                                whole family of display drivers.
;*****************************************************************************/

        .xlist
        include cmacros.inc
INCL_DDIPATHS           equ                      1
INCL_GPIPRIMITIVES      equ                      1
        include pmgre.inc
DINCL_ROPS      equ     1
        include driver.inc
        include polyline.inc
        include njmp.mac
        include assert.mac
        .list

        externA         DOSHUGEINCR

sBegin  Code
        assumes cs,Code

        externNP        dev_polyline_init
        externNP        dev_render_line

;/*
;** Define a DDA running macro.  We use eight specialized loops for
;** speed.  Trying to make it just one leads to too many tests and jumps.
;*/

;/*
;** define the various keywords
;*/

m?dda_huge macro
?dda_huge = 1
endm

m?dda_style macro
?dda_style = 1
endm

m?dda_rotate macro
?dda_rotate = 1
endm

m?dda_short macro
?dda_short = 1
endm

m?dda_devXrot macro
?dda_devXrot = 1
endm

;/*
;**  run_the_dda
;** 
;**  The macro code below handles the ALL of the SideStep logic.  At the
;**  end of the macro it calls off to the run routine to draw CX pels.
;**  The run routine then returns to the top of the macro (notice the
;**  "push" just before the jmp to the RunRoutine).
;**  When cSideSteps has been decremented to zero the line is done except
;**  for the last "partial" run.  The macro jumps off to do_the_last_scan
;**  which is a label near the end of polyline_workhorse_routine.
;*/

run_the_dda     macro   mylist
        local   top_of_run
top_of_run:

;/*
;** determine what arguments we are given
;*/

?dda_huge       = 0
?dda_style      = 0
?dda_short      = 0
?dda_rotate     = 0
?dda_devXrot    = 0

        irp     x,<mylist>
ifdef m?dda_&&x
        m?dda_&&x
else
        ??error2  <run_the_dda - unknown keyword x>
endif
        endm

;/*
;** handle the huge sidestep
;** WARNING: only set HUGE if cbSideStepAddressDelta is not 0 nor 1!
;**    i.e. If the SideStep does not involve a Delta-Y then there is
;**         no way for the SideStep to cross a segment boundary.
;*/

if ?dda_huge
        dec     cScansLeftInSeg
        jnz     @F
        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
@@:
endif ; ?dda_huge

;/*
;**  cbSideStepAddressDelta is the address adjustment for doing a SideStep.
;**  It includes the DeltaY in all cases and includes the deltaX as well
;**  in the case that the runs are diagonal and are to a color bitmap.
;*/

if ?dda_rotate
        ror     bl,1                             ;; mono-bitmap X increment
        adc     di,cbSideStepAddressDelta        ;; mono-bitmap Y increment
else
        add     di,cbSideStepAddressDelta        ;; general SideStep
endif ; ?dda_rotate

;/*
;**  handle device X SideStep increment
;*/

if ?dda_devXrot
        inc     bx
endif ; ?dda_devXrot

;/*
;**  handle styling
;*/


if ?dda_style
        mov     cl,bActiveStyleCounter
        xor     ch,ch
        add     cx,wStyleStepSide
        mov     bActiveStyleCounter,cl
        mov     cl,ch
        and     cl,7
        rol     bActiveStyleMask,cl
endif ; ?dda_style

;/*
;**  go for the next scan
;*/

        dec     cSideSteps
if ?dda_short
        jz      do_the_last_scan
else
        njz     do_the_last_scan
endif

;/*
;**  determine the count for intermediate scans
;*/

        mov     cx,cm
        mov     si,wError
        or      si,si
        js      @F
        inc     cx
        sub     si,lsg.lsg_cdy                    ;; wError -= 1
@@:     add     si,wFracS                         ;; wError += frac(s)
        mov     wError,si

;/*
;**  loop back to the top, while calling the RunRoutine
;*/

        push    CodeOFFSET top_of_run
        jmp     npfnRunRoutine                    ; CX = number of pixels to draw
        endm

;/*
;**  The table of DDA routines.                   
;*/

WDDA_ROTATE     equ     0002h
WDDA_STYLE      equ     0004h
WDDA_HUGE       equ     0008h

        .errnz  WDDA_ROTATE - 2
        .errnz  WDDA_STYLE  - 4
        .errnz  WDDA_HUGE   - 8

dda_table       equ     this word
        dw      dda____
        dw      dda___R
        dw      dda__S_
        dw      dda__SR
        dw      dda_H__
        dw      dda_H_R
        dw      dda_HS_
        dw      dda_HSR

dev_styled_dda_table       equ                      this word
        dw      dda__S_
        dw      dda__SX

;/***************************************************************************
;*
;* FUNCTION NAME = polyline_workhorse_routine
;*
;* DESCRIPTION   = 
;*
;*    the DDA algorithm used here is based on Jack Bresenham's Run Length
;*    Algorithm for Incremental Lines.  NATO ASI Series.  Volume F17.
;*    Fundamental Algorithms for Computer Graphics.  Springer-Verlag
;*    Berlin Heidelberg  1985.
;*
;*    WARNING: this routine is called by DrawLines in DRAWLINE.ASM,
;*          as well as by do_polyline.
;*
;*    Registers Destroyed:
;*          AX,BX,CX,DX,DI,SI
;*    Registers Preserved:
;*          DS,ES
;*
;* INPUT         = DI = cdx            
;*                 SI = cdy            
;*                 BP = polyline frame 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


cProc   setup_poly_frame_dda,<FAR,NODATA>
        include plylocal.inc                    
cBegin  nogen
cEnd    nogen


        assumes ds,nothing
        assumes es,nothing

cProc   polyline_workhorse_routine,<PUBLIC,NEAR,NODATA,NONWIN>
cBegin
        mov     fbControl,0
        mov     iWhichDDA,0

;/*
;**  The device handles solid lines.  It knows how to
;**  run a dda, but it will want the real yA.  Note that if the half flip
;**  flag is set then our values for cdy is not correct.  We need to
;**  "unflip" it here so that the yA we calculate will be true.
;*/
        test    sd_flags,SD_DEVICE
        jz      @F
        cmp     LineStyle,LINETYPE_SOLID - 1     ; styled lines not done in h/w
        jnz     @F
        mov     bActiveStyleMask,0FFh             ; force solid line
        test    di,0F800h                          ; can't do wild coords in h/w
        jnz     @F
        test    si,0F800h                          ; can't do wild coords in h/w
        jnz     @F
        or      fbControl,FBC_HWLINE              ; We will use hardware the dda!
        test    byte ptr lsg.lsg_fsLineFlags,LF_HALF_FLIP
        jz      @F
        sub     si,di
        neg     si                               ; if HALF_FLIP then (dx - dy) gives real dy
        mov     lsg.lsg_cdy,si
        xor     byte ptr lsg.lsg_fsLineFlags[1],1
        .errnz  LF_VERTICAL_FLIP - 100h
@@:

;/*
;**  check for horizontal lines
;*/

        or      si,si
        jnz     non_horizontal
        mov     yA,si
        mov     cSideSteps,si
        mov     ax,lsg.lsg_xB
        sub     ax,lsg.lsg_xA
        inc     ax
        mov     cB,ax
        jmp     know_my_dda
non_horizontal:

;/*
;** On a 16 MHz 386, all the following clip calculations take only
;** 15 microseconds.  This seems to indicate that we don't need a
;** special case for simpler clipping!
;*/

;/*
;**  Compute the various slope quantities:
;**
;**     m = floor(s)            (12)
;**
;**     wFracS = frac(s)        (in units of 1/dy)
;*/

        mov     ax,di
        xor     dx,dx
        div     si
        mov     cm,ax
        mov     wFracS,dx

;/*
;** Compute starting scan, remember that (2 dx) might be 17 bits!  
;**                                                     
;**    y  = ceil((x - f )/s + 1/2) - 1                 
;**     a          a   0                                
;**                                                     
;**       = floor((x - f )/s + 1/2 - 1/(2 dx))       (27) 
;**                 a   0                               
;**                                                     
;**       = floor((2 dy x  - 2 dy f  + dx - 1) / (2 dx))   
;**                      a                          0     
;*/

        add     si,si                             ; SI = (2 dy)
        mov     ax,lsg.lsg_xA                     ; 2 dy xA
        mul     si                                ; 
        mov     bx,di                             ; dx - 1
        dec     bx
        xor     cx,cx
        cmp     byte ptr lsg.lsg_fsLineFlags[1],1 ; -2 dy f   (i.e. +1 if flip)
        .errnz  LF_VERTICAL_FLIP - 100h            ;    0
        cmc
        adc     ax,bx
        adc     dx,cx
        shr     dx,1                              ; / 2
        rcr     ax,1
        adc     cx,cx
        div     di                                ; / dx
        mov     yA,ax                             ; remainder rm = 2 * DX + CX

;/*
;** Compute the first run:
;**
;**    c  = floor(s(y + 1/2) + f ) - x + 1
;**     a            a          0     a
;**                                                    (30)
;**                    rm + 1
;**       = floor( s - ------ ) + 1
;**                     2 dy
;*/

        mov     ax,di
        sub     ax,dx
        xor     dx,dx
        add     ax,ax
        adc     dx,dx
        inc     cx
        sub     ax,cx
        sbb     dx,0                              ; DX:AX = 2 dx - (rm + 1)
        div     si
        inc     ax
        mov     cA,ax

;/*
;** Compute the initial error term:                    
;**                                                     
;**    f' = frac(s(y + 1/2) + f ) + frac(s) - 1                           
;**     1           a          0                        
;**                                                    (31) 
;**                   rm + 1                            
;**       = frac( s - ------ ) + frac(s) - 1.         
;**                    2 dy                             
;*/

;/*
;**  DX is presently frac(s - (rm + 1)/(2 dy)) in units of 1/(2 dy).
;**  If we were to express frac(s) and 1 in units of 1/(2 dy), they would
;**  each be EVEN numbers.  Therefore the bottom bit of f' will be unchanged
;**  whenever we calculate f' <- frac(f') + frac(s) - 1.  This bottom bit
;**  is therefore wasted.  Since (f' >= 0) is unchanged if we turn off the
;**  bottom bit, this is what we will do. On the other hand, f' needs to
;**  be a signed number and we therefore need the top bit to be significant.
;**  The result of all this is that we will shift the bottom bit off of
;**  the unsigned DX, and keep f' (wError) in units of 1/dy.
;*/

        shr     dx,1
        add     dx,wFracS
        sub     dx,lsg.lsg_cdy
        mov     wError,dx                         ; that was easy!

;/*
;** Compute the final scan, remember that (2 dx) might be 17 bits! 
;**                                                     
;**    y  = ceil((x - f )/s + 1/2) - 1                (23) 
;**     b          b   0                                
;**                                                     
;**       = floor((x - f )/s + 1/2 - 1/(2 dx))       (27) 
;**                 b   0                               
;**                                                     
;**       = floor((2 dy x  - 2 dy f  + dx - 1) / (2 dx))   
;**                      b                          0     
;*/

        mov     ax,lsg.lsg_xB                     ; 2 dy xB
        mul     si
        mov     bx,di                             ; dx - 1
        dec     bx
        xor     cx,cx
        cmp     byte ptr lsg.lsg_fsLineFlags[1],1 ; -2 dy f
        .errnz  LF_VERTICAL_FLIP - 100h           ;    0
        cmc
        adc     ax,bx
        adc     dx,cx
        shr     dx,1                              ; / 2
        rcr     ax,1
        adc     cx,cx
        div     di                                ; / dx, remainder rm' = 2 * DX + CX

;/*
;** if both scans are the same, we're clipped to be horizontal
;*/

        sub     ax,yA
        mov     cSideSteps,ax
        jnz     still_non_horizontal
        mov     ax,lsg.lsg_xB
        sub     ax,lsg.lsg_xA
        inc     ax
        mov     cB,ax
        jmp     know_my_dda
still_non_horizontal:

;/*
;** Compute the final run:                              
;**                                                     
;**    c  = x  - floor(s(y - 1/2) + f )                
;**     b    b            b                           0     
;**                                                    (32) 
;**                   rm'+ 1           rm'+ 1         
;**       = - floor(- ------ ) = ceil( ------ )       
;**                    2 dy                              2 dy  
;*/

        mov     ax,dx
        xor     dx,dx
        add     ax,ax
        adc     dx,dx
        inc     cx
        add     ax,cx
        adc     dx,0
        div     si
        neg     dx                                ; round any remainder up
        adc     ax,0
        mov     cB,ax
know_my_dda:

;/*
;** Advance the style mask for clipping.               
;*/

publab  advance_style_mask_clip

        cmp     LineStyle,LINETYPE_SOLID-1
        jz      no_style_adjust
        or      iWhichDDA,WDDA_STYLE
        mov     ax,lsg.lsg_xA
        mov     bx,yA
        sub     ax,bx
        mul     wStyleStepRun
        xchg    ax,bx
        mul     wStyleStepSide
        add     ax,bx
        add     bActiveStyleCounter,al
        adc     ah,0
        mov     cl,ah
        and     cl,7
        rol     bActiveStyleMask,cl
no_style_adjust:

        test    fbControl,FBC_HWLINE             ; use hardware?
        jz      @F
        call    dev_render_line
        jmp     polyline_workhorse_exit
@@:

;/*
;** Rotate the clipped start point and sidestep back to real
;** coordinates so we can calculate surface addresses.
;**-----------------------------------------------------------------------;
;** Two issues are settled below.
;**  o  What is the SideStep delta
;**       i.e. the delta from the end of one run to the beginning of the next.
;**  o  What is the delta to the next pel while in a run
;**       We are only concerned with runs that advance across
;**       scanlines (vertical and diagonal).  The horizontal runs
;**       are trivial (add 1).
;**
;** Most of the work below is to calculate the side step.  We begin with
;** a default of (1,1) => a diagonal step.
;** A step up requires subtraction of the scan size.  A step to the
;** right requires adding 1.  We hold this information as two flags:
;** CL = (move right), CH = (BOOL) (do we move a scan?).
;** We'll also carry along the scan size since it must get negated if
;** we are Y flipped.
;**
;** We will set DX to 0 or 1 to indicate vertical or diagonal runs, resp.
;** The delta to the next pel while in a run is then (+/-)ScanSize + DX
;** (this is all irrelevant if the runs are horizontal)
;*/

publab calc_deltas

;/*
;** load the first pixel
;*/

        mov     bx,lsg.lsg_xA                      ; (BX,AX) = first pixel
        mov     ax,yA

        mov     si,cbScanSize
        neg     si                                ; default up => negative address delta
        mov     cx,101h                           ; CH = move by scan, CL = Xstep bit

;/*
;** HALF FLIP
;*/

        xor     dx,dx
        mov     di,lsg.lsg_fsLineFlags           ; DI = flags
        test    di,LF_HALF_FLIP
        jz      @F
        inc     dx                                ; DX=1 if HALF_FLIP => diagonal run
        sub     ax,bx                             ; y = x - y
        neg     ax
        xor     ch,ch
@@:

;/*
;** XY XCHG
;*/

        test    di,LF_XY_XCHG
        jz      @F
        xchg    ax,bx
        xchg    ch,cl
@@:

;/*
;** Y FLIP
;*/

        test    di,LF_Y_FLIP
        jz      @F
        neg     ax                                ; y = -y
        neg     si
@@:
        test    sd_flags,SD_DEVICE
        njnz    styled_device_lines
        test    sd_flags,SD_COLOR
        jnz     color_format
        xor     dx,dx
color_format:
        add     dx,si                             ; the vertical run routines use SI
        mov     cbScanAddressDelta,dx            ; and the diagonal runs use SI+1 (color)

        neg     ch                                ; Set CF if CH != 0
        sbb     dx,dx                             ; DX = 00 (FF) if CH was 0 (Not 0)
        and     si,dx                             ; Zero SI if CH was 0

        xor     ch,ch
        assert  cx,BE,1
        test    sd_flags,SD_COLOR
        jnz     no_rotate                         ; color => packed pixel => no rotate
        add     cl,cl
        or      byte ptr iWhichDDA,cl
        .errnz  WDDA_ROTATE - 2
        xor     cx,cx
no_rotate:
        add     si,cx                             ; add 1 to SI if CL was 1. (Color only)

;/*
;** Because the mono bitmaps (like EGA bitmaps) have more than one pel per
;** bitmap-byte we must handle X and Y SideStep movements separately.
;** But in color bitmaps we have 1 pel per bitmap-byte, so we have combined
;** the X and Y SideStep movements into cbSideStepAddressDelta.
;*/

        mov     cbSideStepAddressDelta,si ; SI = SideStep delta

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

publab  Compute_surface_addr

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

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

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

        mov     cx,cScansPerSegment
        jcxz    not_huge_surface

;/*
;** If cbSideStepAddressDelta (which is currently SI) is 0 or 1 then
;** there is no delta-Y in the side step.  Therefore we don't need
;** any HUGE update code in the SideStep part of the DDA.
;*/

        cmp     si,1                              ; use: SI = SideStep delta
        jbe     @F
        or      iWhichDDA,WDDA_HUGE
@@:     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  kno_huge_adjust_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    di,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)
;*/

        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                   ; Eliminate var, leave mask in BL !!!
        jmp     short   @F

packed_pixel_addressing:

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

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

;/*
;** Determine the Run Routine.
;*/

publab  Determine_the_Run_Routine

        mov     si,di                            ; LineFlags
        and     si,110b
        .errnz  LF_HALF_FLIP + LF_XY_XCHG - 110b
        add     si,anpfnRunRoutines
        lods    word ptr cs:[si]
        mov     npfnRunRoutine,ax


;/*
;** Setup for a pass (the EGA does multiple passes here).
;*/

publab  setup_for_a_pass

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

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

;/*
;** Run the DDA!                                        ;
;*/

publab  run_that_dda

        mov     bl,bRotBitMask                    ; BL = rotating bit mask

;/*
;** send a single scan to the end
;*/

        cmp     cSideSteps,0
        jz      do_the_last_scan

;/*
;** draw the first scan
;*/

        mov     cx,cA
        mov     si,iWhichDDA
        push    dda_table[si]
        jmp     npfnRunRoutine                    ; CX = number of pixels to draw


;/*
;** our favorite DDA routines
;*/

dda____:        run_the_dda                      <short>

dda___R:        run_the_dda                      <short,rotate>



;/*
;** Finish up the workhorse routine.                   ;
;*/

;/*
;** dump out the last scan
;*/

do_the_last_scan:
        mov     cx,cB
        call    npfnRunRoutine



polyline_workhorse_exit:
cEnd


;/*
;** More DDA routines.                                  ;
;*/

dda__S_:        run_the_dda                      <short    ,style >
dda__SR:        run_the_dda                      <short    ,style,rotate>
dda_H__:        run_the_dda                      <      huge  >
dda_H_R:        run_the_dda                      <      huge  ,rotate>
dda_HS_:        run_the_dda                      <      huge,style >
dda_HSR:        run_the_dda                      <      huge,style,rotate>
dda__SX:        run_the_dda                      <     style,devXrot>


;/*
;** DEVICE STYLED LINES
;**
;** We are doing Styled Lines 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.
;*/

publab   styled_dev_lines
styled_device_lines:

        or      si,si                             ; SI is negative if Y_FLIP clear
        mov     si,1
        jns     @F
        neg     si
@@:
        mov     cbScanAddressDelta,si            ; set deltaY

        neg     ch                                ; Set CF if CH != 0
        sbb     dx,dx                             ; DX = 00 (FF) if CH was 0 (Not 0)
        and     si,dx                             ; Zero SI if CH was 0
        mov     cbSideStepAddressDelta,si ; SI = SideStep X

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

        add     bx,lsg.lsg_xStart                ; BX == pixel in scan == dev X coord
        add     ax,lsg.lsg_yStart
        mov     dx,cySurface                      ; Y=0 is at the top of the screen
        dec     dx                                ;  => invert y coordinate
        sub     dx,ax                             ; DX == scan line == device Y coord

;/*
;** DSL: Determine the Run Routine.                    ;
;*/

        mov     si,di                            ; LineFlags
        and     si,110b
        .errnz  LF_HALF_FLIP + LF_XY_XCHG - 110b
        add     si,anpfnRunRoutines
        lods    word ptr cs:[si]
        mov     npfnRunRoutine,ax

;/*
;** DSL: Run the DDA!                                   ;
;*/

        mov     di,dx

;/*
;** send a single scan to the end
;*/

        cmp     cSideSteps,0
        jz      do_the_last_scan_relay

;/*
;** draw the first scan
;*/

        assert  cl,B,2                           ; CL is still the "rotate" flag
        xor     ch,ch
        add     cx,cx
        mov     si,cx
        .errnz  WDDA_ROTATE - 2
        mov     cx,cA                               ; BX = X coord
        push    dev_styled_dda_table[si]  ; DI = Y coord
        jmp     npfnRunRoutine                      ; CX = number of pixels to draw

do_the_last_scan_relay:
        jmp     do_the_last_scan

sEnd    Code

        end
