;*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 = PLYSOLID.ASM
;*
;* DESCRIPTIVE NAME = Polyline solid line drawing device driver. 
;*
;*
;* VERSION      V2.0
;*
;* DATE         03/30/87
;*
;* DESCRIPTION  This module contains all of the routines called by         
;*              POLYLINE.ASM to draw solid polylines in EGA memory.  The   
;*              routines are basically broken into six different cases.    
;*              Lines are categorized as x major, y major or diagonal.     
;*              They are also broken down into simple and non-simple, or   
;*              standard, cases; where simple means horizontal, vertical or
;*              on a diagonal.  These simple cases can be drawn much faster
;*              than the standard cases, and are therefore broken out from 
;*              the rest.  There are similar routines in POLYBITM.ASM for  
;*              solid lines to bitmaps, and POLYSTYL.ASM for styled lines  
;*              to EGA.  While these routines are all quite similar, they  
;*              are separated purely for speed considerations.             
;*              POLYLINE.ASM is the dispatching module for all of these    
;*              routines, and the run length slice algorithm DDA, which all
;*              of these routines are based on, is explained in that       
;*              module.                                                    
;*                                                                          
;* FUNCTIONS    setup_poly_frame_1
;*              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
;*   10/28/86                     Tony Pisculli [tonyp] Created
;*                                dev_solid_horizontal.
;*   02/23/87                     Kent Settle [kentse] Major re-write of
;*                                dev_solid_horizontal.
;*   04/08/87                     Kent Settle [kentse] Modified
;*                                dev_solid_horizontal to draw all lines
;*                                moving right.
;*   05/08/88                     Charles Whitmer [chuckwh] Rewrote
;*                                dev_solid_horizontal from scratch.  The
;*                                previous code was over twice as long and
;*                                very complicated.
;*                                Charles Whitmer [chuckwh] Pulled this
;*                                code together from several existing
;*                                and then slimmed it down and sped it up.
;*                                Changed it to not advance the address
;*                                after the last pixel.
;*
;*****************************************************************************/

        .xlist
        include cmacros.inc
INCL_DDIPATHS   equ     1
        include pmgre.inc
        include driver.inc
        include display.inc
        include egamemf.inc
        include egafam.inc
        include polyline.inc
        .list

sBegin  Code
        assumes cs,Code

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

        public  dev_solid_horizontal

;/***************************************************************************
;*
;* PUBLIC ROUTINE  dev_solid_horizontal 
;*
;* DESCRIPTION   = Draws a solid horizontal line on the EGA.  
;*
;*                 Registers Destroyed:   
;*                       CX,SI            
;*                 Registers Preserved:   
;*                       DX,BP,ES         
;*
;* INPUT         = DS:DI = EGA address         
;*                 BL = rotating bit mask      
;*                 CX = number of bits to draw 
;*                 DX = EGA_BASE + GRAF_DATA   
;*
;* OUTPUT        = DS:DI = new EGA address    
;*                 BL = new rotating bit mask 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

        align   4

dev_solid_horizontal    proc                     near

;/*
;** calculate the start mask, end mask, and byte count
;*/

        dec     cx                                ; CX = number of bits to move by
        mov     ax,cx
        shr     ax,3                              ; AX = number of bytes to move
        and     cx,7                              ; CX = number of bits to rotate
        mov     bh,bl                             ; BH = initial bit
        ror     bl,cl                             ; BL = ending bit
        mov     cx,ax                             ; CX = number of bytes to move
        mov     ax,bx
        xchg    ah,al                             ; AL = initial bit, AH = ending bit
        neg     ah                                ; AH = ending mask
        add     al,al
        dec     al                                ; AL = initial mask
        cmp     bh,bl                             ; adjust the count for byte wrap
        adc     cx,0                              ; CX = bytes to touch - 1
        jz      just_do_the_last

;/*
;** put out the first byte
;*/

        out     dx,al
        mov     al,0FFh
        or      [di],al
        inc     di

;/*
;** do any intermediate bytes
;*/

        dec     cx
        jz      just_do_the_last
        out     dx,al
output_loop:
        or      [di],al
        inc     di
        loop    output_loop

;/*
;** do the last byte (combine end mask and previous mask)
;*/

just_do_the_last:
        and     al,ah
        out     dx,al
        or      byte ptr [di],0FFh
        ret
dev_solid_horizontal    endp

        public  dev_solid_vertical

;/***************************************************************************
;*
;* PUBLIC ROUTINE  dev_solid_vertical   
;*
;* DESCRIPTION   = Draws a solid vertical line on the EGA.  
;*
;*                 Registers Destroyed:   
;*                       CX,SI            
;*                 Registers Preserved:   
;*                       DX,BP,ES         
;*
;* INPUT         = DS:DI = EGA address         
;*                 BL = rotating bit mask      
;*                 CX = number of bits to draw 
;*                 DX = EGA_BASE + GRAF_DATA   
;*
;* OUTPUT        = DS:DI = new EGA address    
;*                 BL = new rotating bit mask 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* dev_solid_vertical
;* {
;*    // this routine outputs BitCount vertical bits.  therefore, the
;*    // rotating bit mask is contant for all bytes output.
;*
;*    while (BitCount--)
;*    {
;*        output byte to EGA memory;
;*        DI += AddVertStep;                // jump to next scan line.
;*    }
;*                                          // return with BL = rotating bitmask.
;*    return();                             // DS:DI => current destination byte.
;* }
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

        align   4

dev_solid_vertical    proc    near
        mov     si,cbScanAddressDelta

;/*
;** This routine outputs CX vertical bits.  Therefore, the rotating bit
;** mask is constant for all bytes output.  The following section sets up
;** for a loop which outputs eight vertical bytes.  This loop partially
;** unrolled to save time, but not unrolled too far as to waste many bytes.
;*/

        mov     bh,0FFh                           ; useful constant
        mov     al,bl                             ; get rotating bit mask
        out     dx,al
        dec     cx
        jz      vertical_last_pixel
        dec     cx                                ; (we'll fix this with INC AX)
        mov     ax,cx                             ; AX = BitCount
        shr     cx,3                              ; CX = number of times through loop
        inc     cx                                ; adjust for partial loop
        and     ax,7                              ; AX = remainder
        inc     ax                                ; force AX > 0

;/*
;** AX = the number of bits to set for the partial loop. In the loop
;** below it takes 4 bytes to output each pixel, so AX is multiplied by 4.
;*/

        shl     ax,2
        neg     ax
        add     ax,CodeOFFSET y_axial_end_of_final_loop
        jmp     ax

        even                                      ; align on a word boundary
y_axial_final_loop:
        or      [di],bh                           ; output the byte
        add     di,si                             ; jump to next scan line
.errnz  ($ - y_axial_final_loop) - 4
        or      [di],bh
        add     di,si
        or      [di],bh
        add     di,si
        or      [di],bh
        add     di,si
        or      [di],bh
        add     di,si
        or      [di],bh
        add     di,si
        or      [di],bh
        add     di,si
        or      [di],bh
        add     di,si
y_axial_end_of_final_loop:
        loop    y_axial_final_loop
vertical_last_pixel:
        or      [di],bh
        ret
dev_solid_vertical    endp

        public  dev_solid_diagonal

;/***************************************************************************
;*
;* PUBLIC ROUTINE  dev_solid_diagonal   
;*
;* DESCRIPTION   = Draws a solid diagonal line on the EGA.  
;*
;*                 Registers Destroyed:   
;*                       CX,SI            
;*                 Registers Preserved:   
;*                       DX,BP,ES         
;*
;* INPUT         = DS:DI = EGA address         
;*                 BL = rotating bit mask      
;*                 CX = number of bits to draw 
;*                 DX = EGA_BASE + GRAF_DATA   
;*
;* OUTPUT        = DS:DI = new EGA address    
;*                 BL = new rotating bit mask 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* dev_solid_diagonal
;* {
;*    // this routine draws BitCount diagonal bits.  since we are drawing
;*    // a diagonal segment, x and y coordinates will change with each
;*    // bit drawn.
;*
;*    while (BitCount--)
;*    {
;*        output byte to EGA memory;
;*        rotate bit mask;
;*        increment DI if done with byte;
;*        DI += AddVertStep;                // jump to next scan line.
;*    }
;*
;*    BL = rotating bit mask;
;*                                          // return with BL = rotating bitmask,
;*    return();                             // DS:DI => current destination byte.
;* }
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

        align   4

dev_solid_diagonal    proc    near
        mov     al,bl                             ; get the bit mask
        mov     bh,0FFh
        mov     si,cbScanAddressDelta
        dec     cx
        jz      diagonal_last_pixel
diagonal_loop:
        out     dx,al                             ; set up bitmask register
        or      [di],bh                           ; output byte to EGA memory
        ror     al,1                              ; rotate the bit mask
        adc     di,si                             ; next scan line
        loop    diagonal_loop
diagonal_last_pixel:
        out     dx,al                             ; set up bitmask register
        or      [di],bh                           ; output byte to EGA memory
        mov     bl,al
        ret
dev_solid_diagonal    endp

sEnd    Code

        end
