;*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 = DRAWBITS.ASM
;*
;* DESCRIPTIVE NAME = DrawBits at level of device driver. 
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/11/90
;*
;* DESCRIPTION  Draws a portion of standard-formatted Bitmap directly onto the 
;*              screen
;*                                                            
;*               . The standard-formatted Bitmap can have 1/4/8/24 bits/pel   
;*                 but only one plane.                           
;*               . length in byte of 1 scan does not exceed 64k    
;*               . The target device 3/4 plane EGA/VGA display                
;*               . No RasterOperations are supported and direct copy is done. 
;*               . Bound checking of the source rectangle is done against the 
;*                 screen extents before in DrawBits, BitBlt,                 
;*                 enumerate_clip_rects, and do_drawbits.     
;*               . Returns 1 in AX to indicate success (0 => failure)         
;*
;* FUNCTIONS    OEMDrawBits
;*              copy_1_bp_full
;*              copy_4_bp_full
;*              copy_8_bp_full
;*              copy_24_bp_full
;*              get_byte_wo_test
;*              get_byte_with_test
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   12/06/88                     Amit Chatterjee  [amitc] Created for Windows
;*                                for DIScreenBlt
;*   05/11/90                     Viroon Touranachun [viroont] Adapted for PM
;*
;*****************************************************************************/

        .286P

        .xlist
        include cmacros.inc
INCL_GPIBITMAPS         equ                      1       ; for bitmap info structure
        include pmgre.inc
        include driver.inc
        include display.inc
        include egafam.inc
        include egamemf.inc
        include assert.mac
        include iodelay.inc
        .list

        CPUMode 386

        externFP    far_exclude         ; CURSORSC.ASM
        externFP    far_unexclude       ; CURSORSC.ASM
        externA     SCREEN_DSCAN        ; EGAMEMD.ASM
        externA     DOSHUGEINCR
        externA     DOSHUGESHIFT

sBegin  PtrData
        externB     shadowed_graf_mode
sEnd    PtrData

sBegin  Code
        assumes cs,Code
        assumes ds,Data
        assumes es,nothing

        externNP    RLEDrawBits                 ; RLEBM.ASM
        externNP    rgb_to_ipc                  ; PHYCOLOR.ASM
        externNP    clean_up_before_exit_no_test; EXIT.BLT

        externW     MyPtrCodeData

;/*
;**   Tables for BitCount-dependent routines
;*/

FullXFer        equ     this word                ; has the xfer routine addresses
                dw      CodeOFFSET copy_1_bp_full
                dw      CodeOFFSET copy_4_bp_full
                dw      CodeOFFSET copy_8_bp_full
                dw      CodeOFFSET copy_24_bp_full

InitProc        equ     this word                ; has the init routine addresses
                dw      CodeOFFSET odb_init_1_bit_per_pel
                dw      CodeOFFSET odb_init_4_bits_per_pel
                dw      CodeOFFSET odb_init_8_bits_per_pel
                dw      CodeOFFSET odb_init_24_bits_per_pel

ODB_SRC_HUGE    equ     01h             ;indicate the huge source bitmap

;/***************************************************************************
;*
;* FUNCTION NAME = OEMDrawBits
;*
;* DESCRIPTION   = This function is a working routine to draw a              
;*                 standard-formatted bitmap directly (ROP_SRCCOPY) to the   
;*                 screen.                                                   
;*
;*                 Calls:
;*                       clean_up_before_exit_no_test
;*                       far_exclude
;*                       far_unexclude
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   OEMDrawBits,<FAR,PUBLIC,WIN,PASCAL>,<si,di>

        parmD   pddcDst                           ;Destination ddc
        parmW   xDst                              ;Destination x origin
        parmW   yDst                              ;Destination y origin
        parmD   psdSrc                            ;Source surface definition
        parmW   xSrc                              ;Source x origin
        parmW   ySrc                              ;Source y origin
        parmW   cxExt                             ;x extent of the BLT
        parmW   cyExt                             ;y extent of the BLT

        localD  lpBits                            ; pointer to the caller-supplied bits
        localW  cbSrcScan                         ; offset to next map scan
        localD  lpScreen                          ; pointer to start byte of screen
        localW  cbDstScan                         ; offset to next screen scan
        localW  cBitCount                         ; no of bits per source pel
        localD  lpClrTab                          ; pointer to the color mapping table
        localB  bBitMask                          ; the mask for the current bit
        localB  fbFlags                           ; flag bytes
        localW  pfnFullXfer                       ; the routine to call to blt a byte/scan
        localW  pfnGetByte                        ; holds address of fetch proc
        localW  cbSrcScanBlt                      ; no of bytes in source for 1 scan blt
        localB  bUnusedPel                        ; used for first byte src mask for 1,4bpp
        localW  cPelsAtATime                      ; used for 1 bit per pel case

cBegin

;/*
;** Get the bitmap information
;*/

        cld
        les     si,psdSrc               ; source surface definition
        mov     ax,es:[si].bm_sd.sd_cbScan
        mov     cbSrcScan,ax            ; source scan width in bytes
        mov     eax,es:[si].bm_sd.sd_pBits
        mov     lpBits,eax              ; pointer to the caller-supplied bits
        mov     eax,dword ptr es:[si].bm_sd.sd_pClrTab
        mov     lpClrTab,eax            ; pointer to the color mapping table
        les     si,dword ptr es:[si].bm_sd.sd_pbmi; pointer to the bitmap info
        mov     cx,es:[si].bmp_cBitCount; the number of bits per pel (assume old)
        cmp     es:[si].bmp2_cbFix,size BITMAPINFOHEADER
        je      short odb_have_info     ; it's old header, we know it's uncomp.

;/*
;** OEMDrawBits only draws the uncompressed bitmap. If it is a compressed bitmap
;** this is a good chance to pass it to RLEDrawBits.
;*/

odb_new_header:
        mov     cx,es:[si].bmp2_cBitCount   ;the number of bits per pel
        cmp     es:[si].bmp2_cbFix,bmp2_ulCompression
        jbe     short odb_have_info         ;must be uncompressed

odb_check_compress:
        cmp     es:[si].bmp2_ulCompression,BCA_UNCOMP
        je      short odb_have_info
        arg     pddcDst                           ;Destination ddc
        arg     xDst                              ;Destination x origin
        arg     yDst                              ;Destination y origin
        arg     es                                ;Source bitmap info structure
        arg     si
        arg     xSrc                              ;Source x origin
        arg     ySrc                              ;Source y origin
        arg     cxExt                             ;x extent of the BLT
        arg     cyExt                             ;y extent of the BLT
        arg     lpBits                            ;pointer to RLE encoded buffer
        arg     lpClrTab                          ;pointer to the color mapping table
        cCall   RLEDrawBits
        jmp     odb_end                           ;already draw to screen

odb_have_info:
        mov     cBitCount,cx

;/*
;** we shall also calculate no of bytes in the source map that correspond to
;** cxExt bits, as we shall use this information to test whether we cross a seg-
;** ment on the source during the blt of cxExt pels on a scan.
;*/

        mov     ax,cxExt                          ; get the no of bits in 1 scan blt
        mul     cx                                ; multiply by no of bits per pel
        assert  dx,E,0
        shr     ax,3                              ; get the number of bytes
        add     ax,1                              ; take the ceiling
        mov     cbSrcScanBlt,ax


;/*
;** Cursor Exclusion for a device destination
;*/

odb_cursor_exclude:
        mov     si,cxExt
        mov     di,cyExt
        dec     si                                ;Make extents inclusive of last point
        dec     di
        mov     cx,xDst                           ;Set left
        mov     dx,yDst                           ;Set top
        add     si,cx                             ;Set right
        add     di,dx                             ;Set bottom
        cCall   far_exclude                       ;Exclude the area from the screen

;/*
;** calculate the offset to the start byte in the map and the screen and the   
;** position of the first pel in the screen byte and on the map.              
;*/

odb_calc_src_offset:
        mov     ax,ySrc                           ; get the Y origin of the map
        mul     cbSrcScan                         ; the result is in DX:AX
        mov     bx,ax
        mov     cx,dx                             ; result in CX:BX
        mov     ax,xSrc                           ; get the starting X pel no
        mul     cBitCount                         ; no of bits per pel
        assert  dx,E,0
        shr     ax,3                              ; get the no of bytes
        add     ax,bx                             ; add in the contribution on CX:BX
        adc     dx,cx                             ; DX:AX has the offset

;/*
;** add in the contribution of the original start offset of the bits.
;*/

        add     lpBits.off,ax                     ; update the offset
        adc     dx,0                              ; incase this causes another wrap
        mov     cx,DOSHUGESHIFT
        shl     dx,cl
        add     lpBits.sel,dx                     ; update the segment part of ptr


;/*
;**  lpbits now points to the first byte of the map in the blt area.           
;**  The starting scan no might not have crossed a segment but the blt area   
;**  might still cross a segment, test for that.           
;*/
                
        mov     ax,cyExt                          ; get the Y ext of the blt
        mul     cbSrcScan                         ; bytes per scan on the map
        add     ax,lpBits.off                     ; add the first byte offset
        adc     dx,0                              ; if dx is 0 we do not cross a segment
        setnz   dl                                ; DL = 1 if cross segment
        .errnz  ODB_SRC_HUGE-1
        or      fbFlags,dl                        ; will have to test for segment update

;/*
;** now calculate the address of the start byte in the screen blt area.       
;*/

odb_calc_dst_offset:
        mov     cbDstScan,SCREEN_DSCAN            ; destination scan width in bytes
        mov     ax,yDst                           ; get the Y origin (top scan)
        add     ax,cyExt                          ; move it to the bottom of scan
        dec     ax
        mul     cbDstScan                         ; no of bytes in a scan
        assert  dx,E,0
        mov     bx,xDst                           ; get the x origin
        mov     cx,bx
        shr     bx,3                              ; get the no of bytes
        add     ax,bx                             ; this is the start offset 
        mov     lpScreen.off,ax
        les     si,pddcDst                        ; ES:SI => the dest. ddc
        assumes es,nothing
        mov     si,es:[si].ddc_npsd               ; ES:SI => the dest. surface
        mov     ax,es:[si].sd_pBits.sel           ; the screen segment
        mov     lpScreen.sel,ax

;/*
;** lpScreen now has the pointer to the first byte in the screen blt area      
;** Calculate the position of the first bit in the first byte of the screen    
;** blt area.                                                
;*/

odb_set_bit_mask:
        and     cl,07h                            ; get the bit no in the starting byte
        mov     bl,80h                            ; starting mask
        shr     bl,cl                             ; bl has the correct bit set
        mov     bBitMask,bl                       ; save it

;/*
;** now get the address of the full and partial byte proces that we will be    
;** using depending on the bits per pel.
;*/

odb_get_xfer_addr:
        mov     bx,cBitCount            ; get the bits per pel
        shl     bx,4                    ; if BX = 1 => BX = 0
        shl     bh,6                    ; if BX = 4 => BX = 1
        add     bh,bl                   ; if BX = 8 => BX = 2
        shr     bx,14                   ; if BX = 24 => BX = 3
        shl     bx,1                    ; double for word offset
        mov     ax,FullXFer[bx]         ; get the transfer routine
        mov     pfnFullXfer,ax
        mov     bx,InitProc[bx]                   ; get the appropriate init procs addr
        jmp     bx                                ; do the format specific inits

;/*
;**  the format specific initialization routines follow here.       
;**  ES:DI points to the color table.                              
;**                                                                             
;**  For monochrome, we need to know how many bits in the first source byte     
;**     (from the left) are unused and init color table                         
;**  For 4 bpp, we need to know wheter we start with the high nibble or the     
;**     low nibble and init the color table.                                    
;**  For 8 bpp, we always have each pel starts at the byte boundary, so just    
;**     init the color table.                                                   
;**  For 24 bpp, do nothing.                                                    
;*/                                                                             


odb_init_1_bit_per_pel:
        mov     ax,xSrc                           ; the start pel number in a scan
        and     ax,7                              ; the number of pel unused in 1st byte
        mov     bUnusedPel,al
        jmp     short odb_init_8_bits_per_pel
           
odb_init_4_bits_per_pel:
        mov     ax,xSrc                           ; start BMP pel number in a byte
        shr     ax,1                              ; if odd we start with low nibble
        rcl     bUnusedPel,1                      ; LSB bit for low nibble usage

odb_init_8_bits_per_pel:
        lgs     bx,lpClrTab                       ; the color mapping table
        assumes gs,nothing

odb_init_24_bits_per_pel:

;/*
;** we will program the EGA/VGA GRX registers to be in write mode 0, where the
;** CPU value can be used to write masked pixels.
;*/

odb_init_board:
        mov     es,MyPtrCodeData                 ; Show color read mode to the
        assumes es,PtrData                       ;   EGA restoration code
        mov     dx,EGA_BASE + GRAF_ADDR          ; the GRX controller address

;/*
;** set up for READ 0/WRITE 2
;*/

        mov     ax,(M_COLOR_WRITE shl 8)+GRAF_MODE
        mov     es:shadowed_graf_mode.vvr_value,ah ; Must shadow this for state code
        out     dx,ax

        DevIODelay                                ;I/O delay destroys ax

;/*
;** set up the GRX address register with the index for the bit mask
;** register.
;*/

        mov     al,GRAF_BIT_MASK
        out     dx,al

        DevIODelay                                ;I/O delay destroys ax

;/*
;** The sorce bytes in a scan may cross a segment boundary only if the flag -  
;** ODB_SRC_HUGE is set.                                     
;**                                                          
;** If the flag is set a test will be made at the start of every scan line to  
;** see whether that scan crosses the segment boundary or not. If it does cross
;** a segment boundary, every byte will be fetched with a test to detect the   
;** segment cross if not then 'LODSB' will be used to get the byte.      
;**                                                          
;** We assume that a scan will not cross two segment boundaries.              
;*/

odb_start_draw:
        lds     si,lpBits                         ; the strting point of the bits
        assumes ds,nothing
        les     di,lpScreen                       ; the start on the screen
        assumes es,nothing

        mov     cx,cyExt                          ; the number of scans to copy
        mov     dx,EGA_BASE + GRAF_DATA           ; will alaways have this value

;/*
;** We will draw one scan at a time so that we can determine which
;** byte-transfer routines we will use. First, assume that segment crossings
;** will not be required for this scan.
;*/

odb_blt_next_scan:
        mov     pfnGetByte,CodeOFFSET get_byte_wo_test
        test    fbFlags,ODB_SRC_HUGE             ; will the blt cross a segment
        jz      short odb_blt_next_scan_continue ; segment crossing check not required

;/*
;** test to see if the current scan will span a segment
;*/

        mov     ax,si                            ; set current offset
        add     ax,cbSrcScanBlt                  ; no of bytes involved in 1 scan blt
        jnc     short odb_blt_next_scan_continue ; this scan will be within segment
        or      ax,ax                            ; the last byte of the scan could be
        jz      short odb_blt_next_scan_continue ; the last byte of segment

;/*
;** the scan will cross a segment somewhere, so use the pfnGetByte proc which tests
;** for segment crossings
;*/

        mov     pfnGetByte,CodeOFFSET get_byte_with_test

odb_blt_next_scan_continue:
        push    cx                                ; save scan loop count
        push    ds                                ; save map segment
        push    si
        push    di                                ; save the source and target pointers
        mov     ah,bBitMask                       ; the starting mask
        mov     cx,cxExt                          ; the no of pels to blt
        cCall   pfnFullXfer                       ; do the blt of a scan
        pop     di
        pop     si                                ; get back the pointers
        pop     ds
        pop     cx                                ; get back the no of scans left to blt
        sub     di,cbDstScan                      ; we map top to bottom
        add     si,cbSrcScan                      ; update to the next scan
        jc      short odb_new_scan_in_segment     ; the new scan is in segment
        loop    odb_blt_next_scan                 ; blt all the scans
        jmp     short odb_exit                    ; we are done with the last scan

;/*
;** the new scan crosses a segment, has to be in the next segment, so take DS
;** into the next segment
;*/

odb_new_scan_in_segment:
        dec     cx
        jcxz    odb_exit                          ; do not update selector if done
        mov     ax,ds                             ; get current DS
        add     ax,DOSHUGEINCR                    ; update to the next segment
        mov     ds,ax
        jmp     short odb_blt_next_scan           ; blt all the scans

;/*
;** now reset the EGA/VGA parameters and bring back the cursor
;*/

odb_exit:
        cCall   clean_up_before_exit_no_test      ; restore EGA registers
        cCall   far_unexclude                     ; re-draw the cursor

odb_end:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = copy_1_bp_full
;*
;* DESCRIPTION   = handles the blt of a scan or a part of it for 1 bits per
;*                 pixel case                                              
;*
;*                 Registers Destroyed:
;*                       AL,CX,flags   
;*
;* INPUT         = DS:SI     --  current byte in the map     
;*                 ES:DI     --  current byte in the screen     
;*                    AH     --  current bit position in the first byte 
;*                 GS:BX     --  address of color mapping table 
;*                    CX     --  number of pels to convert      
;*                    DX     --  BIT MASK register address      
;*
;* OUTPUT        = DS:SI,ES:DI -- next bytes in respective areas
;*                 AH          -- updated bit mask 
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
        
        assumes ds,nothing
        assumes es,nothing

cProc   copy_1_bp_full,<NEAR,PUBLIC>

cBegin  <nogen>

;/*
;** the first source byte may yield partial number of pels
;** shift left the contents till the start pel is on left edge
;*/

        cCall   pfnGetByte                        ; get the first byte
        push    cx                                ; save
        mov     cl,bUnusedPel                     ; no of pels not used in 1st byte
        shl     al,cl                             ; the first pel is on the edge
        neg     cl      
        add     cl,8                              ; the number of pels left in byte
        xor     ch,ch
        mov     cPelsAtATime,cx
        pop     cx

copy_1_bp_loop:
        xchg    al,ah                             ; get the current mask
        push    cx                                ; save # to convert

;/*
;** cPelsAtATime has the number of pels in the byte, usually 8 except for first
;** and last
;*/

        cmp     cx,cPelsAtATime                   ; 8 or more bits left
        jbe     short copy_1_bp_same_byte         ; no partial byte
        mov     cx,cPelsAtATime                   ; convert the 8 bits in the byte

copy_1_bp_same_byte:
        push    cx                                ; save mask and byte
        out     dx,al                             ; set up the mask register
        shl     ah,1                              ; get the next oel into carry
        rcl     cl,1                              ; get the pel value
        and     cl,1                              ; only 1 bit significant
        xchg    al,cl                             ; save mask in cl, get pel in al
        xlat    gs:[bx]                           ; get the converted value
        xchg    es:[di],al                        ; write the pel
        mov     al,cl                             ; get the mask in al
        ror     al,1                              ; next bit position
        adc     di,0                              ; update screen pointer if needed
        pop     cx                                ; get back byte and mask
        loop    copy_1_bp_same_byte               ; convert the byte
        pop     cx                                ; get back remaining bits
        mov     ah,al                             ; get back mask in ah
        sub     cx,cPelsAtATime                   ; 8 or less were just converted
        jbe     short copy_1_bp_done              ; CX <= 0 means we have done all
        cCall   pfnGetByte                        ; get the next byte
        mov     cPelsAtATime,8                    ; do 8 bits in it
        jmp     short copy_1_bp_loop              ; continue in loop

copy_1_bp_done:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = copy_4_bp_full 
;*
;* DESCRIPTION   = handles the blt of a scan or a part of it for 4 bits per 
;*                 pixel case                                               
;*                                                                          
;*                 Registers Destroyed:                                                          
;*                       AL,CX,flags                                                             
;*                                                                          
;* INPUT         = DS:SI  --  current byte in the map      
;*                 ES:DI  --  current byte in the screen    
;*                 AH     --  current bit position in the first byte 
;*                 GS:BX  --  address of color mapping table                                                            
;*                 CX     --  number of pels to convert 
;*                 DX     --  BIT MASK register address  
;*                                                                          
;* OUTPUT        = DS:SI,ES:DI --  next bytes in respective areas 
;*                 AH          --  updated bit mask    
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   copy_4_bp_full,<NEAR,PUBLIC>

cBegin  <nogen>

        cCall   pfnGetByte                        ; process first byte separately
        test    bUnusedPel,1                      ; is just the low nibble to be used
        jnz     short copy_4_bp_low_nibble        ; yes
        jmp     short @F                          ; already fetch the 1st byte

copy_4_bp_loop:
        cCall   pfnGetByte                        ; get the next source byte
@@:
        xchg    al,ah                             ; get the mask into al
        out     dx,al                             ; set up the pel mask for 1 pel
        xchg    al,ah                             ; get back byte in al
        push    ax                                ; save the byte
        shr     al,4                              ; get the high nibble into low pos
        xlat    gs:[bx]                           ; get the mapping index
        xchg    es:[di],al                        ; write the pel
        pop     ax                                ; get back pel
        ror     ah,1                              ; rotate mask
        jnc     short copy_4_bp_next_nibble       ; process low nibble of source
        inc     di                                ; position to next target byte

copy_4_bp_next_nibble:
        dec     cx                                ; one more pel done
        jcxz    copy_4_bp_done

copy_4_bp_low_nibble:
        xchg    al,ah                             ; get the mask into al
        out     dx,al                             ; set up the mask
        xchg    al,ah                             ; get back the pel in al
        and     al,0fh                            ; get the lower 4 bits
        xlat    gs:[bx]                           ; get the mapping index
        xchg    es:[di],al                        ; write the pel
        ror     ah,1                              ; the next bit position in the mask
        jnc     short copy_4_bp_next_byte         ; continue xfer
        inc     di                                ; next target  byte

copy_4_bp_next_byte:
        loop    copy_4_bp_loop                    ; process all the remaining pels

copy_4_bp_done:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = copy_8_bp_full
;*
;* DESCRIPTION   = handles the blt of a scan or a part of it for 8 bits per
;*                 pixel case                                              
;*                                                                         
;*                 Registers Destroyed:   
;*                      AL,CX,flags      
;*
;* INPUT         = DS:SI     --  current byte in the map     
;*                 ES:DI     --  current byte in the screen    
;*                    AH     --  current bit position in the first byte 
;*                 GS:BX     --  address of color mapping table 
;*                    CX     --  number of pels to convert      
;*                    DX     --  BIT MASK register address     
;*
;* OUTPUT        = DS:SI,ES:DI -- next bytes in respective areas
;*                          AH -- updated bit mask  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   copy_8_bp_full,<NEAR,PUBLIC>

cBegin  <nogen>

        cCall   pfnGetByte                        ; get the next source byte
        xchg    al,ah                             ; get the mask into al
        out     dx,al                             ; set up the mask for 1 pel
        xchg    al,ah                             ; get back the byte in al
        xlat    gs:[bx]                           ; get the mapping index value
        xchg    es:[di],al                        ; write the pel
        ror     ah,1                              ; rotate the mask for the next bit
        jnc     short copy_8_bp_loop              ; continue with same target byte
        inc     di                                ; the next screen byte

copy_8_bp_loop:
        loop    copy_8_bp_full                    ; repeat till all bytes processed
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = copy_24_bp_full
;*
;* DESCRIPTION   = handles the blt of a scan or a part of it for 24 bits per
;*                 pixel case                                              
;*                                                                         
;*                 Registers Destroyed:   
;*                      AL,BX,CX,flags   
;*
;* INPUT         = DS:SI     --  current byte in the map     
;*                 ES:DI     --  current byte in the screen    
;*                    AH     --  current bit position in the first byte 
;*                    CX     --  number of pels to convert      
;*                    DX     --  BIT MASK register address     
;*
;* OUTPUT        = DS:SI,ES:DI -- next bytes in respective areas
;*                          AH -- updated bit mask  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   copy_24_bp_full,<NEAR,PUBLIC>

cBegin  <nogen>

        push    dx
        push    ax                                ; save the bytes to be destroyed
        cCall   pfnGetByte                        ; get the blue pel
        mov     dl,al                             ; have blue in dl
        cCall   pfnGetByte                        ; get green
        mov     ah,al                             ; have it in ah
        cCall   pfnGetByte                        ; get red in al
        xchg    dl,al                             ; DL = red, AH = green, AL = blue
        cCall   rgb_to_ipc                        ; do the mapping => AL = physical color
        pop     dx                                ; DH = current bit position
        mov     ah,dh                             ; move it to AH
        pop     dx                                ; get the other values back
        and     al,MM_ALL                         ; have just the index bits
        xchg    al,ah                             ; get the mask into al
        out     dx,al                             ; set up the mask for the bit
        xchg    al,ah                             ; get the mask back into ah
        xchg    es:[di],al                        ; xfer the pel
        ror     ah,1                              ; select the next bit for mask
        jnc     short copy_24_bp_loop             ; screen will have same byte
        inc     di                                ; go the next screen byte

copy_24_bp_loop:
        loop   copy_24_bp_full                    ; process all the other bytes
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = get_byte_wo_test
;*
;* DESCRIPTION   = This routine is used to fetch a byte when no segment       
;*                 crossing need to be tested.
;*
;* INPUT         = DS:SI     --      current byte in the map       
;*
;* OUTPUT        = DS:SI     --      next bytes in respective areas      
;*                 AL        --      byte fetched
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   get_byte_wo_test,<NEAR,PUBLIC>

cBegin  <nogen>

        lodsb                                     ; get the next byte 
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = get_byte_with_test
;*
;* DESCRIPTION   = This routine is used to fetch a byte when the scan at some
;*                 point will cross a segment.
;*
;* INPUT         = DS:SI     --      current byte in the map       
;*
;* OUTPUT        = DS:SI     --      next bytes in respective areas      
;*                 AL        --      byte fetched
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   get_byte_with_test,<NEAR,PUBLIC>

cBegin  <nogen>

        lodsb                                     ; get the current byte
        or      si,si                             ; si wraps to 0 ?
        jz      short get_byte_xing_segment       ; no, we are in same segment
        ret                                       ; get back

cEnd    <nogen>

get_byte_xing_segment:
        mov     si,ds                             ; get current segment
        add     si,DOSHUGEINCR                    ; go to the next segment
        mov     ds,si                             ; update segment

;/*
;** here we assume that the rest of the current scan will not cross a segment
;** boundary again, so will use the shorter get byte proc
;*/

        mov     pfnGetByte,CodeOFFSET get_byte_wo_test
        xor     si,si
        ret

sEnd    Code

        public  odb_new_header
        public  odb_have_info
        public  odb_cursor_exclude
        public  odb_calc_src_offset
        public  odb_calc_dst_offset
        public  odb_set_bit_mask
        public  odb_get_xfer_addr
        public  odb_init_1_bit_per_pel
        public  odb_init_4_bits_per_pel
        public  odb_init_8_bits_per_pel
        public  odb_init_24_bits_per_pel
        public  odb_init_board
        public  odb_start_draw
        public  odb_blt_next_scan
        public  odb_blt_next_scan_continue
        public  odb_new_scan_in_segment
        public  odb_exit

        end
