;*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_3
;*                                    
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*****************************************************************************/

        .386

        .xlist

INCL_GPIPRIMITIVES      equ     1
INCL_DDIPATHS           equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1

        .list

        include pmgre.inc
        include driver.inc
        include display.inc
        include polyline.inc
        include extern.inc
        include protos.inc
if SCAN_CNT EQ 768
        include oem_macs.inc
endif

        .list

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

        .DATA

        .CODE
        
        OPTION PROLOGUE:None

        OPTION EPILOGUE:None

;/***************************************************************************
;*
;* FUNCTION NAME = setup_poly_frame_3 
;*
;* DESCRIPTION   = A grouping of the public labels:
;*                 
;*                 dev_solid_horizontal 
;*                 dev_solid_vertical 
;*                 dev_solid_diagonal 
;*                 
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
ALIGN 4
setup_poly_frame_3  PROC SYSCALL
LOCAL   returnvalue:DWORD,
        dwStyleCounter:DWORD,
        Flags:DWORD,
        Count:DWORD,
        Points:DWORD
LOCAL   npddc:DWORD,
        dwStyleMask:DWORD, 
        npfnUnSetup:DWORD,
        CurLineColor:DWORD,
        DrawModeIndex:DWORD,
        cPlanes:DWORD
LOCAL   cbNextPlane:DWORD,
        dwBitmapROP:DWORD,
        dwStyleStepHorz:DWORD,
        dwStyleStepVert:DWORD,
        dwStyleStepDiag:DWORD
LOCAL   dwStyleStepHorzTmp:DWORD,
        dwStyleStepVertTmp:DWORD,
        offNextLine:DWORD,
        cbScanSize:DWORD,
        cbHugeScanWrap:DWORD,
        cySurface:DWORD   
LOCAL   cScansPerSegment:DWORD, 
        pSurfaceStart:DWORD,
        anpfnRunRoutines:DWORD,
        LineStyle:DWORD,  
        npfnPassSetup:DWORD,
        cPasses:DWORD,
        lsg:LINESEGMENT
LOCAL   dwStyleStepRun:DWORD,
        dwStyleStepSide:DWORD,
        dwActiveStyleCounter:DWORD,
        dwActiveStyleMask:DWORD,
        yA:DWORD,
        cScans:DWORD,      
        cA:DWORD,         
        cB:DWORD,
        cm:DWORD
LOCAL   npfnRunRoutine:DWORD,
        iWhichDDA:DWORD,
        dwError:DWORD,
        dwFracS:DWORD,
        dwRotBitMask:DWORD, 
        cbScanAddressDelta:DWORD, 
        cbSideStepAddressDelta:DWORD,
        cbHugeScanDelta:DWORD,          
        selHugeDelta:DWORD,  
        dwScan:DWORD       
LOCAL   pSurfaceAddress:DWORD,
        cTmpScans:DWORD,          
        dwTmpError:DWORD,
        dwTmpScan:DWORD,          
        dwTmpRotBitMask:DWORD,  
        dwTmpActiveStyleCounter:DWORD,
        dwTmpActiveStyleMask:DWORD,
        cTmpPasses:DWORD,
        TmpCurLineColor:DWORD
if SCAN_CNT EQ 768
                        LOCAL   start_bank:DWORD
endif

        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
;*
;**************************************************************************/

dev_solid_horizontal::

        DebugMsg <dev_solid_horizontal, plysolid, CLIFFL>

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

        dec     ecx                               ; CX = number of bits to move by
        mov     eax,ecx
        shr     eax,3                             ; AX = number of bytes to move
        and     ecx,7                             ; CX = number of bits to rotate
        mov     bh,bl                             ; BH = initial bit
        ror     bl,cl                             ; BL = ending bit
        mov     ecx,eax                           ; CX = number of bytes to move
        mov     eax,ebx
        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     ecx,0                             ; CX = bytes to touch - 1
        jz      just_do_the_last

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

        out     dx,al
        mov     al,0FFh
        or      BYTE PTR [edi],al
        inc     edi

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

        dec     ecx
        jz      just_do_the_last
        out     dx,al

output_loop:

        or      BYTE PTR [edi],al
        inc     edi
        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 [edi],0FFh
        ret

        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.
;* }
;*
;**************************************************************************/

if SCAN_CNT EQ 768
ALIGN 4
dev_solid_vertical::


        DebugMsg <dev_solid_vertical, plysolid, CLIFFL>


        mov     esi,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     ah,0FFh                           ; useful constant
        mov     al,bl                             ; get rotating bit mask
        mov     ebx, dwScan
        out     dx,al
        dec     ecx
        jz      vertical_last_pixel

        even
y_axial_final_loop:
        or      [edi], ah
        add     edi,esi
        dec     ebx
        loopnz  y_axial_final_loop
        jnz     vertical_last_pixel

;/*
;** there was a huge overflow
;*/

        push    eax
        push    edx

        mov     edx,start_bank
        add     edx,selHugeDelta
        mov     start_bank,edx
        SetBankRW

        mov     eax,010000h
        cmp     edi,pVRAMInstance
        jb      @F
        neg     eax
@@:
        add     edi,eax

        mov     ebx, cScansPerSegment

        pop     edx
        pop     eax

        or      ecx,ecx
        jnz     y_axial_final_loop

vertical_last_pixel:
        or      [edi],ah
        mov     dwScan,ebx
        mov     bl,al
        ret

;/***************************************************************************
;*
;* 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.
;* }
;*
;**************************************************************************/

public dev_solid_diagonal
ALIGN 4
dev_solid_diagonal::
        mov     al,bl                             ; get the bit mask

        mov     ah,0FFh
        mov     ebx,dwScan
        mov     esi,cbScanAddressDelta
        dec     ecx
        jz      diagonal_last_pixel
diagonal_loop:

;/*
;** output a pixel
;*/

        out     dx,al                             ; set up bitmask register
        or      BYTE PTR [edi],ah                ; output byte to EGA memory
        ror     al,1                              ; rotate the bit mask

;/*
;** move to next scan line
;*/

        adc     edi,esi                           ; next scan line
        dec     ebx                               ; jn 10-4-89, check for huge overflow
        loopnz  diagonal_loop
        jnz     diagonal_last_pixel

;/*
;** there was a huge overflow
;*/

        push    eax
        push    edx

        mov     edx,start_bank
        add     edx,selHugeDelta
        mov     start_bank,edx
        SetBankRW

        mov     eax,010000h
        cmp     edi,pVRAMInstance
        jb      @F
        neg     eax
@@:
        add     edi,eax

        mov     ebx,cScansPerSegment

        pop     edx
        pop     eax

        or      ecx,ecx
        jnz     diagonal_loop

diagonal_last_pixel:
        out     dx,al                             ; set up bitmask register
        or      BYTE PTR [edi],ah                 ; output byte to EGA memory
        mov     dwScan,ebx
        mov     bl,al
        ret

else ;768

ALIGN 4
dev_solid_vertical::


        DebugMsg <dev_solid_vertical, plysolid, CLIFFL>


        mov     esi,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     ecx
        jz      vertical_last_pixel
        dec     ecx                               ; (we'll fix this with INC AX)
        mov     eax,ecx                           ; AX = BitCount
        shr     ecx,3                             ; CX = number of times through loop
        inc     ecx                               ; adjust for partial loop
        and     eax,7                             ; AX = remainder
        inc     eax                               ; 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     eax,2
        neg     eax
        add     eax,OFFSET y_axial_end_of_final_loop
        jmp     eax
ALIGN 4

y_axial_final_loop:

        or      BYTE PTR [edi],bh      ; output the byte
        add     edi,esi                           ; jump to next scan line

.errnz  ($ - y_axial_final_loop) - 4

        or      BYTE PTR [edi],bh
        add     edi,esi
        or      BYTE PTR [edi],bh
        add     edi,esi
        or      BYTE PTR [edi],bh
        add     edi,esi
        or      BYTE PTR [edi],bh
        add     edi,esi
        or      BYTE PTR [edi],bh
        add     edi,esi
        or      BYTE PTR [edi],bh
        add     edi,esi
        or      BYTE PTR [edi],bh
        add     edi,esi

y_axial_end_of_final_loop:

        loop    y_axial_final_loop

vertical_last_pixel:

        or      BYTE PTR [edi],bh
        ret

        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.
;* }
;*
;**************************************************************************/

ALIGN 4
dev_solid_diagonal::


        DebugMsg <dev_solid_diagonal, plysolid, CLIFFL>

        mov     al,bl                             ; get the bit mask
        mov     bh,0FFh
        mov     esi,cbScanAddressDelta
        dec     ecx
        jz      diagonal_last_pixel

diagonal_loop:

        out     dx,al                             ; set up bitmask register
        or      BYTE PTR [edi],bh                 ; output byte to EGA memory
        ror     al,1                              ; rotate the bit mask
        adc     edi,esi                           ; next scan line
        loop    diagonal_loop

diagonal_last_pixel:

        out     dx,al                             ; set up bitmask register
        or      BYTE PTR [edi],bh                 ; output byte to EGA memory
        mov     bl,al
        ret
endif ;768

setup_poly_frame_3  ENDP

        end
