;*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 = pldevsup.asm
;*
;* DESCRIPTIVE NAME = Polyline drawing device driver. 
;*
;*
;* VERSION      V2.0
;*
;* DATE         06/06/87
;*
;* DESCRIPTION  
;*
;*     This file contains run routines for drawing solid and styled lines to the
;*     8514 display device.  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.  The 8514 handles lines in hardware.  We just give it the      
;*     appropriate arguments, and it does the drawing.  Drawing to bitmaps must 
;*     be done the hard way.  There are sixteen raster operations (sets of      
;*     logical operations) performed on the data written out.  The 8514 handles 
;*     all this for us.  Unlike the EGA all 8514 lines are drawn in a single    
;*     pass, including lines to bitmaps.  This is because our bitmaps use       
;*     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    cProc   setup_poly_frame_1
;*              device_unsetup 
;*              dev_polyline_init   
;*              dev_render_line     
;*              dev_solid_horizontal
;*              dev_solid_vertical  
;*              dev_solid_diagonal  
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   06/06/87                     Author: Wes Rupel   (wesleyr)
;*   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/20/88                     Bob Grudem [bobgru] Implemented the "max"
;*                                metric for line styling.
;*   06/21/88                     Wes Rupel [wesleyr] EGA --> 8514 Massive
;*                                Changes.
;*   09/16/88                     Bob Grudem [bobgru] Gathered all the
;*                                device-dependent supporting subroutines in a
;*                                single module for easier maintenance.
;*   10/03/88                     Bob Grudem [bobgru] Assumption about 16-bit
;*                                division rectified.
;*****************************************************************************/

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

        public  device_unsetup
        public  dev_polyline_init
        public  dev_render_line

        public  dev_solid_table

        public  dev_solid_horizontal
        public  dev_solid_vertical
        public  dev_solid_diagonal


sBegin  PtrData
        externB screen_busy                          ; screen busy semaphore
sEnd    PtrData

        externFP far_qdiv                            ; MATH.ASM

sBegin  Code
        assumes cs,Code

        externW MyPtrCodeData                        ; for access to pointer data segment

        externW         dev_styled_table             ; PLSTYLE.ASM

        externB         FarhwMixes                   ; hwdata.asm - 8514 Mix Equivalents
        externA         hwMixes_tblSize              ; hwdata.asm

;/*
;** the various line rendering routines
;*/

dev_solid_table         equ                      this word
        dw      dev_solid_horizontal
        dw      dev_solid_vertical
        dw      dev_solid_diagonal
        dw      dev_solid_diagonal


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


device_unsetup  proc    near
        ReleaseScreen  polyline,far,Code    ; cursor can do its thing
        ret
device_unsetup  endp


;/***************************************************************************
;*
;* FUNCTION NAME = dev_polyline_init
;*
;* DESCRIPTION   = Initializes stack frame variables and sets up 8514         
;*                 registers that will not need to be altered on a per-line
;*                 basis.
;*
;*                 Registers Destroyed:
;*                       AX,BX,DX
;*                 Registers Preserved:
;*                       BP,DS,ES
;*
;* INPUT         = DS:DI => DDC 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

dev_polyline_init       proc                     near

        push    es
        GrabScreen polyline,far,Code               ; don't let cursor kill us
        pop     es          ; Only DrawLinesInPath needs this preserved.
                            ; We could push/pop there, but so far we haven't
                            ; had to alter that file for this driver...

        WaitQ   7           ; 6 = 1 Color + 2 Mixes + 2 Patterns
                            ;                    + 1 WRITE_ENABLE + 1 MODE

;/*
;** set color 0.  Color 1 is irrelevant because BackMix is LeaveAlone (always)
;*/

publab  color_0
        outbQ   COLOR_0,CurLineColor

;/*
;** set function 0
;*/

publab  funct_0
        mov     bx,DrawModeIndex    ; get the raster op (ddc_la.la_ba.ba_bmix)
        assert  bx,B,hwMixes_tblSize
        mov     al,FarhwMixes[bx]
        assert  al,B,FUNC_2OP_COL1
        outbQ   FUNCTION_0,al
        .errnz  FUNC_2OP_COL0

;/*
;** set function 1  ==  BackMix.                   This is always LeaveAlone
;*/

        outwQ   FUNCTION_1,< FUNC_D or FUNC_2OP_COL1 >

;/*
;** set pattern 0 and pattern 1
;*/

publab  load_pat
        LoadPattern      00h                     ; Yes, this means display all pels

;/*
;** Enable all planes
;*/

        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES

publab  set_mode
        mov     ax,MD_PS_PATT or MODE_2DECODE
        cmp     LineStyle,LINETYPE_SOLID - 1
        jz      not_styled_lines
        mov     ax,MD_PS_VAR or MODE_2DECODE
not_styled_lines:
        outwQ   MODE,ax

        mov     npfnUnSetup,CodeOFFSET device_unsetup
        mov     cScansPerSegment,0                ; Not Huge
        ddc?    di
        mov     bx,[di].ddc_npsd                  ; get ptr to surface definition
        mov     ax,[bx].sd_cy
        mov     cySurface,ax                      ; height of destination

        mov     ax,[bx].sd_cbScan
        mov     cbScanSize,ax

        mov     ax,CodeOFFSET dev_solid_table
        cmp     LineStyle,LINETYPE_SOLID - 1
        jz      @F                                 ; solid lines
        mov     ax,CodeOFFSET dev_styled_table
@@:
        mov     anpfnRunRoutines,ax                ; ignored if lines not styled

;/*
;** Set Scissor Rect to edge of Screen
;*/

        WaitQ   4

        mov     ax,XMIN_2DECODE
        outwQ   XMIN,ax

        mov     ax,YMIN_2DECODE
        outwQ   YMIN,ax

        mov     ax,cbScanSize                     ; width
        assert  ax,BE,1024
        or      ax,XMAX_2DECODE
        outwQ   XMAX,ax

        mov     ax,cySurface                      ; height
        assert  ax,BE,768
        or      ax,YMAX_2DECODE
        outwQ   YMAX,ax

        ret
dev_polyline_init       endp

;/***************************************************************************
;*
;* FUNCTION NAME = dev_render_line
;*
;* DESCRIPTION   = Draws the line segment on the 8514. 
;*
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI
;*                 Registers Preserved:
;*                       BP
;*
;* INPUT         = DI = cdx            
;*                 BP = polyline frame
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

dev_render_line       proc    near
ifdef FIREWALLS
        lea     ax,lsg                        ; for debugging use
        lea     ax,lsg.lsg_xStart             ; for debugging use
endif

;/*
;**  ----------------------------------------------------------------------- 
;**                                                        
;**   For a full explanation of the line drawing algorithm used by the 8514  
;**   see section 11.2.2 in Foley and Van Dam.  This is called   
;**   "reference 3" in the IBM documentation.            
;**                                                        
;**   ET is the initial value of the error term.         
;**   K1 is the is the increment that is added to the error term after each  
;**      pel is drawn.                                     
;**   K2 When the error term goes from negative to nonnegative K2 is added  
;**      to the error term instead of K1.  This makes the error term  
;**      negative again.                                   
;**                                                        
;**   Correcting Algorithmic Differences                  
;**   ----------------------------------                  
;**                                                        
;**   In cases where the geometric line passes exactly half-way between two  
;**   pels this 8514 algorithm rounds the opposite way from what we do in  
;**   our bitmaps.  Here's how we correct this:                              
;**                                                        
;**   The error term is D = S - T (see the book).  But S + T = 1 so   
;**   D = 2S - 1.  At any integer (x value) N, S will be frac(Ndy/dx).  
;**   Thus S is always a multiple of 1/dx and D is always a multiple of  
;**   2/dx.  So if we want to trick the 8514 into thinking that our line  
;**   is slightly lower than it actually is (so the round off will go the  
;**   other way) then we can subtract 2/dx from our initial error term and  
;**   the only pels it should effect are the ones that are being rounded.  
;**                                                        
;**   But note that the error term they use is really dx(S - T) so the  
;**   number we should subtract is 2 rather than 2/dx.  Two is the maximum  
;**   we should subtract.  It will be better code if we just do a DEC AX.  
;**                                                        
;**   Clipping                                             
;**   --------                                             
;**                                                        
;**   xStart and yStart define the unclipped first point in the line.  
;**   (If LEFT_XCHG is set then it is technically the last point).   
;**   X  and X  are the clipped first and last X values relative to xStart  
;**    a      b                                            
;**                                                        
;**   (We have already done flipping so that all lines are X-major).  
;**   The book gives simple                                
;**   formulas for K1, K2, and the initial value of ET.  But this assumes  
;**   we really start at the point (xStart,yStart).  If we clip then we  
;**   must calculate the value ET should have at X   and use that instead.  
;**                                                         a     
;**   Calculating ET:                                      
;**                                                        
;**   ET(0) = 2 * dy - dx                                  
;**   This is the value the book gives for the initial ET. I call it  
;**   ET(0) to indicate that this is the value of ET when X  = 0   
;**                                                           a   
;**                                                        
;**   We need a way to calculate ET(N) for any interger N without actually  
;**   iterating thru all the integers in between.  Here's how:               
;**                                                        
;**   ET(N) =  ( ( ET(0) + N * K1 - K2) mod (K1 - K2) ) + K2   
;**                                                        
;**   Explanation:                                         
;**                 The algorithm adds K1 to ET for each step (X value)  
;**   until ET is nonnegative.  Then it adds K2 instead which makes ET  
;**   negative again (K2 is negative).                    
;**                                                        
;**   Let's define K3 = K1 - K2.  Now we can say we always add K1, and if    
;**   ET was nonnegative before we added then we also subtract K3. This  
;**   is completely equivalent -- but easier to think about.   
;**                                                        
;**   Since K1 is always added we just multiply N * K1 to find out how  
;**   much K1 added to ET(N).  Now we just subtract K3 repeatedly until  
;**   ET is negative.  This gives the not-quite-right formula   
;**                                                        
;**   ET(N) =  ( ( ET(0) + N * K1) mod K3 ) - K3         
;**                                                        
;**   The mod takes care of all but one of the subtractions.  So we do the  
;**   last one explicitly at the end.                     
;**                                                        
;**   It is incorrect because ET can have a positive value.    
;**   To be precise:  K1 > ET >= K2  (remember K2 is negative).   
;**   So what we should really do is subtract K3 as many times as   
;**   necessary until ET is less than K1.  To fix the above formula we  
;**   just subtract K1 from the argument to "mod K3" and then add the K1  
;**   back on afterwards:                                  
;**                                                        
;**   ET(N) =  ( ( ET(0) + (N - 1) * K1) mod K3 ) - K3 + K1    
;**                                                        
;**   This equation works fine if N is large.  But small values of N can  
;**   give negative arguments to "mod K3".           To avoid this we simply add  
;**   K3 to the argument.  That wont alter the result of the mod if the  
;**   argument was already positive, and it makes the argument positive  
;**   for all the negative arguments we will encounter.  This gives:  
;**                                                        
;**   ET(N) =  ( ( ET(0) + (N - 1) * K1 + K3 ) mod K3 ) - K3 + K1   
;**                                                        
;**   Putting back K1 - K2 for K3 gives our desired equation:   
;**                                                        
;**   ET(N) =  ( ( ET(0) + N * K1 - K2) mod (K1 - K2) ) + K2   
;**                                                        
;**    Wed 06-Jul-1988 21:17:27                      -by- Wes Rupel [wesleyr]  
;**   Figured out all the stuff above.                    
;**  ----------------------------------------------------------------------- 
;*/

        mov     bl,byte ptr lsg.lsg_fsLineFlags  ; BL = flags

        WaitQ   8                                ; one wait for each out[wb]Q


publab  set_lx

;/*
;** set LX  ----- Number of Pels in the line minus 1
;*/

        mov     ax,lsg.lsg_xB
        sub     ax,lsg.lsg_xA
        outwQ   LX,ax

publab  set_x0          ; set X0  ----- initial value of X coordinate

        mov     ax,lsg.lsg_xA
        mov     cx,yA
        test    bl,LF_XY_XCHG
        jz      xmajor_is_default
        xchg    ax,cx
xmajor_is_default:
        add     ax,lsg.lsg_xStart
        mov     usX0,ax
        outwQ   X0,ax

publab  set_y0          ; set Y0  ----- initial value of Y coordinate

        mov     ax,cySurface                     ; surface top is at low addresses
        dec     ax                               ;  => invert y coordinate
        sub     ax,lsg.lsg_yStart                ; 
        test    bl,LF_Y_FLIP
        jz      @F
        neg     cx
@@:     sub     ax,cx
        outwQ   Y0,ax


publab  set_k1          ; set K1   -----  2 * cdy  (cdy is the MinorAxisLen)

        xor     cx,cx
        mov     si,lsg.lsg_cdy
        add     si,si
        adc     cx,cx                            ; 2dy might be 17 bits, but the hardware
        mov     ax,si                            ; register only holds 16 bits...
        mov     ulK1.lo,ax
        mov     ulK1.hi,cx
        outwQ   K1,ax                            ; 2 * dy  ==  CX:SI  == CX:AX

publab  set_et0         ;  ET(0)   -----  2 * cdy - cdx   (uncorrected)

        assert  di,E,lsg.lsg_cdx
        sub     ax,di                            ; 2 * dy - dx
        sbb     cx,0
        mov     si,ax                            ; CX:SI == ET(0) uncorrected ==
        mov     dx,cx                            ; DX:AX == ET(0) uncorrected
        test    bl,LF_Y_FLIP                     ; test if round-off correction needed.
        jnz     skip_correction
        sub     ax,1
        sbb     dx,0
skip_correction:
        mov     ulET.lo,ax
        mov     ulET.hi,dx


publab  set_k2          ; set K2   -----  2 * dy - 2 * dx

        sub     si,di                            ; CX:SI == ET(0) uncorrected == 2 * dy - dx ==
        sbb     cx,0                             ; K2 + dx => so we just subtract cdx from CX:SI
        mov     ulK2.lo,si
        mov     ulK2.hi,cx
        outwQ   K2,si                            ; Once again there are only 16 hardware bits...

publab  set_et          ;  ET(N)

        mov     ax,lsg.lsg_xA
        or      ax,ax
        njz     N_is_zero,F

;/*
;** -----------------------------------------------------------------------;
;**  ET(N) =  ( ( ET(0) + N * K1 - K2) mod (K1 - K2) ) + K2  ;
;** -----------------------------------------------------------------------;
;**  There is the problem that it seems like I really should be doing
;**  calculations with more than 16 bits, but the 8514 only takes 16.
;**  So I carry along with 32 bits as long as possible, then plug the
;**  low word out the the port when I'm done.
;*/

        mul     ulK1.lo                    ; N * K1
        assert  ulK1.hi,E,0
        sub     ax,ulK2.lo                 ; - K2
        sbb     dx,ulK2.hi                 ; 
        assert  NO
        add     ax,ulET.lo                 ; + ET(0)
        adc     dx,ulET.hi                 ; 
        assert  NO

        mov     si,ulK1.lo                 ; 
        mov     cx,ulK1.hi                 ; CX:SI = K1
        sub     si,ulK2.lo                 ; 
        sbb     cx,ulK2.hi                 ; CX:SI = K1 - K2 = K1 + |K2| = Big Number
        assert  NO                         ; The need for > 16 bits will be seen here 1st

        or      dx,dx
        jnz     @F
        jcxz    do_16_bit_div
@@:

;/*
;** DX:CX:BX:AX = UQUAD Numerator
;** SI:DI       = ULONG Denominator
;*/

        push    bx                               ; save flags
        mov     di,si
        mov     si,cx                            ; denominator: SI':DI' = CX:SI
        mov     bx,dx
        xor     cx,cx
        xor     dx,dx                            ; numerator:  DX':CX':BX':AX' = 0:0:DX:AX
        cCall   far_qdiv
        assert  NO
        mov     dx,bx                            ; store remainder in DX
        assert  CX,E,0
        pop     bx                               ; restore flags
        jmp     short div_is_done

do_16_bit_div:
        div     si

div_is_done:
        add     dx,ulK2.lo                       ; The MOD is the remainder (in DX), add K2 and
        mov     ulET.lo,dx                       ; we're done.
N_is_zero:
        mov     ax,ulET.lo
        outwQ   ERR_TERM,ax                      ; Only 16 bits!

;/*
;** --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---;
;**  SetUp and send out Command
;** 
;**  Command/Flag register                          Our Value
;** 
;**  Bits 15-13    command                          (= vector)
;**  Bit  12       Byte Order                       (=0)
;**  Bit  11                                        (=0)
;**  Bit  10                                        (=0)
;**  Bit   9       Byte/^Word data (=0)
;**  Bit   8       ^Fixed/Variable data             (= fixed = 0)
;**  Bits  7-5     DY,DZ,DX
;**  Bit   4       ^Move/Access                     (= Access = 1)
;**  Bit   3       Coded Direction Flag             (=0 => use ET, K1, K2)
;**  Bit   2       Last Pel Null
;**  Bit   1       Allow Pel Accrual (=1)
;**  Bit   0       ^Read/Write                      (= write = 1)
;** --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---;
;*/

publab  set_vec
        tmpflags = CMD_C_VECTOR or CMD_DX or CMD_MA_ACCESS
        mov     ax,tmpflags or CMD_PA_FOUR or CMD_RW_W
        test    bl,LF_XY_XCHG                     ; Is it Y-major?
        jz      its_x_major
        or      ax,CMD_DZ                         ; Set the Y-major bit
its_x_major:
        test    bl,LF_Y_FLIP                      ; Is Delta-Y positive?
        jz      decreasing_y
        or      ax,CMD_DY                         ; Set the IncreasingY bit
decreasing_y:                                     ; Remember the 8514 Y is 0 at Top
        outwQ   CMD_FLAGS,ax
no_line_to_draw:
        ret
dev_render_line       endp


;/***************************************************************************
;*
;* FUNCTION NAME = dev_solid_horizontal
;*
;* DESCRIPTION   = Draws a solid horizontal line on the 8514.  This is only  
;*                 called by PolyShortLine (arcs).  PolyLine uses the 8514
;*                 hardware to draw solid lines.
;*
;*                 Registers Destroyed:
;*                       AX,CX,DX
;*                 Registers Preserved:
;*                       SI,DI,BP
;*
;* INPUT         = BX = X coordinate           
;*                 DI = Y coordinate           
;*                 CX = number of pels to draw 
;*
;* OUTPUT        = BX = last X coord drawn to 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

dev_solid_horizontal     proc                     near
        assert  cx,A,0
        WaitQ   4
        dec     cx
        outwQ   LX,cx                            ; Number of Pels in the line - 1
        outwQ   X0,bx                            ; set X0
        outwQ   Y0,di                            ; set Y0
        tmpflags = CMD_C_VECTOR or CMD_MA_ACCESS
        mov     ax,tmpflags or CMD_PA_FOUR or CMD_RW_W or CMD_CODED_DIR
        outwQ   CMD_FLAGS,ax                     ; draw the line!
        add     bx,cx                            ; advance the X coordinate
        ret
dev_solid_horizontal     endp


;/***************************************************************************
;*
;* FUNCTION NAME = dev_solid_vertical
;*
;* DESCRIPTION   = Draws a stlyed vertical line on the 8514. 
;*
;*                 Registers Destroyed:
;*                       AX,CX,DX
;*                 Registers Preserved:
;*                       BX,SI,BP
;*
;* INPUT         = BX = X coordinate           
;*                 DI = Y coordinate           
;*                 CX = number of pels to draw 
;*
;* OUTPUT        = DI = last Y coord drawn to 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

dev_solid_vertical    proc    near
        assert  cx,A,0
        WaitQ   4
        dec     cx
        outwQ   LX,cx                            ; Number of Pels in the line - 1
        outwQ   X0,bx                            ; set X0
        outwQ   Y0,di                            ; set Y0
        tmpflags = CMD_C_VECTOR or CMD_DZ or CMD_DY or CMD_MA_ACCESS
        mov     ax,tmpflags or CMD_PA_FOUR or CMD_RW_W or CMD_CODED_DIR
        cmp     cbScanAddressDelta,1             ; is either 1 or -1
        jz      @F
        neg     cx
        and     al,not CMD_DY                    ; going up, not down
@@:
        outwQ   CMD_FLAGS,ax                     ; draw the line!
        add     di,cx                            ; advance the Y coordinate
        ret
dev_solid_vertical    endp


;/***************************************************************************
;*
;* FUNCTION NAME = dev_solid_diagonal
;*
;* DESCRIPTION   = Draws a stlyed diagonal line on the 8514. 
;*
;*                 Registers Destroyed:
;*                       AX,CX,DX
;*                 Registers Preserved:
;*                       SI,BP
;*
;* INPUT         = BX = X coordinate           
;*                 DI = Y coordinate           
;*                 CX = number of pels to draw 
;*
;* OUTPUT        = BX = last X coord drawn to
;*                 DI = last Y coord drawn to
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing


dev_solid_diagonal    proc    near
        assert  cx,A,0
        WaitQ   4
        dec     cx
        outwQ   LX,cx                            ; Number of Pels in the line - 1
        outwQ   X0,bx                            ; set X0
        outwQ   Y0,di                            ; set Y0
        add     bx,cx                            ; advance the X coordinate
        tmpflags = CMD_C_VECTOR or CMD_DX or CMD_DY or CMD_DZ or CMD_MA_ACCESS
        mov     ax,tmpflags or CMD_PA_FOUR or CMD_RW_W or CMD_CODED_DIR
        cmp     cbScanAddressDelta,1             ; is either 1 or -1
        jz      @F
        neg     cx
        and     al,not (CMD_DY or CMD_DZ)        ; going up, not down
@@:
        outwQ   CMD_FLAGS,ax                     ; draw the line!
        add     di,cx                            ; advance the Y coordinate
        ret
dev_solid_diagonal    endp

sEnd    Code

        end
