;*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 = DRAWBITS.ASM
;*
;* DESCRIPTIVE NAME = DrawBits at level of device driver. 
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/16/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    Setup8514Rect                                        
;*              SegmentBoundaryProc24                                
;*              SegmentBoundaryProc14                                
;*              NextSegmentDS                                        
;*              SaveParameters                                       
;*              RestoreParameters                                    
;*              Transfer24BitDIB                                     
;*              Transfer148BitDIB                                    
;*              drawbits_rgb_to_ipc                                  
;*                                            
;* NOTES        NONE                          
;*                                            
;* STRUCTURES   NONE                       
;*                                            
;* EXTERNAL REFERENCES                                             
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/16/88                     Gunter Zieber [GunterZ]
;*                                Created for         for DIScreenBlt
;*   12/06/88                     Amit Chatterjee  [amitc] Created for Windows
;*                                for DIScreenBlt
;*   05/16/90                     Viroon Touranachun [viroont] Adapted for PM
;*
;*****************************************************************************/

        .286P

        .xlist
        include cmacros.inc
INCL_GPIBITMAPS         equ                      1       ; for bitmap info structure
INCL_GPILOGCOLORTABLE   equ                      1
        include pmgre.inc
        include driver.inc
        include display.inc
        include 8514.inc
        include assert.mac
        include palette.inc
        .list

        CPUMode 386

        externFP    far_exclude                  ; CURSORSC.ASM
        externFP    far_unexclude                ; CURSORSC.ASM
        externFP    MapDownPaletteIndex          ; colormat.asm
        externFP    far_rgb_to_ipc_with_pal      ; colormat.asm

        externA     DOSHUGEINCR
        externA     DOSHUGESHIFT


;/*
;**    Local data structures
;*/


ParameterBlock  struc
        oCount          dw                       ?
        wStartSkip      dw                       ?
        bStartRem       db                       ?
        bRem            db                       ?
ParameterBlock  ends

sBegin  Data
        externW     BoardMaxY           ;max real addressable y on board
sEnd

sBegin  PtrData
        externB     screen_busy         ;cursor exclusion flag
sEnd    PtrData

sBegin  Code
        assumes     cs,Code

        externW     MyPtrCodeData

        externNP    rgb_to_ipc
        externNP    RLEDrawBits

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

        assumes ds,Data
        assumes es,nothing


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
        localW  cBitCount                         ; no of bits per source pel
        localD  lpClrTab                ; pointer to the color mapping table
        localB  bMask
        localB  bShiftCount
        localB  iInnerCount
        localB  bOldBlue
        localB  bOldGreen
        localW  npfnTransferFunction
        localW  npfnSegCrossProc
        localW  npCurSrcScan
        localW  usOldSegmentPixelCount
        localW  usBoardHeight
        localB  fbPal
ODB_PALETTE     equ     00000001b
ODB_PAL_INDICES equ     00000010b
        localV  Current, %(size ParameterBlock)
        localV  SaveParam, %(size ParameterBlock)

cBegin

        cld

        xor     al,al
        mov     fbPal,al

;/*
;**    Get 8514 BPP mode, the device palette and the appropriate color table
;*/

        mov     ax,BoardMaxY
        mov     usBoardHeight,ax

        lds     si,pddcDst
        assumes ds,nothing
        test    [si].ddc_fbBelow,DDC_PALETTE
        jz      odb_get_bmi
        or      fbPal,ODB_PALETTE


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

odb_get_bmi:
        lds     si,psdSrc               ;source surface definition
        assumes ds,nothing
        mov     ax,ds:[si].bm_sd.sd_cbScan
        mov     cbSrcScan,ax
        mov     eax,ds:[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
        lds     si,dword ptr ds:[si].bm_sd.sd_pbmi; pointer to the bitmap info
        assumes ds,nothing
        mov     cx,ds:[si].bmp_cBitCount;the number of bits per pel (assume old)
        cmp     ds:[si].bmp2_cbFix,size BITMAPINFOHEADER
        je      short odb_full_rgb_tab  ;if old header, we will have full RGBs


;/*
;**  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,ds:[si].bmp2_cBitCount      ;the number of bits per pel
        cmp     [si].bmp2_cbFix,bmp2_ulColorEncoding
        jbe     short odb_colorencoding_ok
        cmp     [si].bmp2_ulColorEncoding,BCE_PALETTE
        jne     short odb_colorencoding_ok
        or      fbPal,ODB_PAL_INDICES

odb_colorencoding_ok:
        cmp     ds:[si].bmp2_cbFix,bmp2_ulCompression
        jbe     short odb_full_rgb_tab

odb_check_compress:
        cmp     ds:[si].bmp2_ulCompression,BCA_UNCOMP
        je      short odb_get_color_count
        arg     pddcDst                           ;Destination ddc
        arg     xDst                              ;Destination x origin
        arg     yDst                              ;Destination y origin
        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     ds:[si].bmp2_ulCompression        ;compression scheme
        arg     lpClrTab                          ;pointer to the color mapping table

        cCall   RLEDrawBits
        jmp     odb_end

odb_get_color_count:
        cmp     ds:[si].bmp2_cbFix,bmp2_cclrUsed
        jbe     short odb_full_rgb_tab
        assert  ds:[si].bmp2_cclrUsed.hi,E,0
        mov     dx,ds:[si].bmp2_cclrUsed.lo       ;number of color used
        or      dx,dx                             ;0 mean use default number of colors
        jnz     short odb_have_info

odb_full_rgb_tab:
        mov     dx,1
        shl     dx,cl                   ;DX = 2^cBitCount

odb_have_info:
        mov     cBitCount,cx
        dec     dx
        mov     bMask,dl                ;1s set for each bit in pixels

;/*
;**    Initialize BitCount-dependent parameters
;*/

        cmp     cBitCount,24
        jne     short odb_Not24BitDIB

odb_init_24_bpp:
        mov     ax,cxExt                          ;24 Bits/pixel DIB specific stuff here
        mov     Current.oCount, ax                ;oCount=X extent
        mov     ax,xSrc                           ;wStartSkip = 3*xSrc
        shl     ax,1
        add     ax,xSrc
        mov     Current.wStartSkip, ax            ;StartSkip=byte offset to actual pixels
        xor     al,al                             ;in current line
        mov     Current.bRem,al                   ;bRem=0
        mov     Current.bStartRem,al              ;bStartRem=0
        mov     ax,CodeOFFSET Transfer24BitDIB
        lea     bx,SegmentBoundaryProc24          ;BX = Segment boundary xing function
        jmp     short odb_TransferSelected

odb_Not24BitDIB:
        mov     ax,8
        div     cl                                ;AL=iInnerCount=8/BitsPixel
        mov     iInnerCount,al                    ;compute inner loop count
        movzx   bx,al                             ;compute #of bytes to skip
        mov     ax,xSrc                           ;and Start Rem = xSrc%iInnerCount
        xor     dx,dx
        div     bx
        mov     Current.wStartSkip,ax
        mov     Current.bStartRem,dl
        mov     ax,cx                             ;AX = cBitCount

odb_AllignmentLoop:
        shr     al, 1                             ;compute remainder allignment shift
        jc      short odb_AllignmentLoopEnd       ;if 8 BitsPixel(BP) -> bRem always 0
        inc     ah                                ;if 4 BP -> bRem 0 or 1
        jmp     short odb_AllignmentLoop          ;if 1 BP -> bRem 0, 1, ..., 7

odb_AllignmentLoopEnd:
        mov     al,ah                             ;keep remainder allignment shift cnt
        push    ax                                ;on stack until use
        mov     ax,cx                             ;shift count=BitsPixel%8
        and     al,07h
        mov     bShiftCount,al                    ;compute pixel to pixel shift count
        mov     ax,cx
        mul     cxExt
        mov     bx,ax
        and     al,07h                            ;rem=cxExt*BitsPixel%8
        pop     cx                                ;get remainder allignment shift count
        shr     al,cl
        mov     Current.bRem, al                  ;compute outer loop remainder
        shrd    bx,dx,3
        shr     dx,3
        mov     al,Current.bStartRem              ;adjust outer count and remainder to
        mov     ah,Current.bRem                   ;take pixels in partial bytes at the
        sub     ah,al                             ;start into account as well
        jnc     short odb_OuterCountOkay
        dec     bx
        add     ah,iInnerCount

odb_OuterCountOkay:
        mov     Current.bRem,ah                  ;save adjusted remainder
        mov     Current.oCount,bx                ;save adjusted outer count
        lea     ax,Transfer148BitDIB             ;select proper transfer routines
        lea     bx,SegmentBoundaryProc148

odb_TransferSelected:
        mov     npfnTransferFunction, ax
        mov     npfnSegCrossProc, bx

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

;/*
;**    Setup the screen parameters
;*/

odb_set_up_screen:
        GrabScreen  OEMDrawBits                   ; don't let cursor operations kill us
        cCall   Setup8514Rect                     ; set dimensions, issue write command
        lds     ax,lpBits                         ; setup source pointer
        assumes ds,nothing
        cmp     cBitCount,24
        je      short @F
        lgs     bx,lpClrTab                      ; gs:bx->translate table
        assumes gs,nothing
@@:
        mov     npCurSrcScan,ax

;/*
;**    Calculate the starting byte address
;*/

odb_calc_src_offset:
        mov     ax,ySrc                           ;offset initial pointer by ySrc
        mul     cbSrcScan                         ;DX=# of segments to advance
        add     npCurSrcScan,ax                   ;AX=offset to pixels
        mov     cx,DOSHUGESHIFT
        shl     dx,cl
        mov     ax,ds
        add     ax,dx
        mov     ds,ax
        mov     dx,COLOR_1                        ;write directly to the board
        mov     al,bMask                          ;put pixel mask into DI (hi byte=0ffh)
        mov     ah,0ffh
        mov     di,ax

odb_TransferLoop:
        mov     ax,npCurSrcScan
        mov     si,ax
        add     ax,cbSrcScan                     ;anticipate no seg. bound. crossing
        mov     npCurSrcScan,ax
        jnc     short odb_NoSegmentCrossing
        cCall   npfnSegCrossProc                 ;do proper seg. bnd. crossing
        jmp     short odb_BottomOfTransferLoop

odb_NoSegmentCrossing:
        cCall   npfnTransferFunction             ;now do first half of this line

odb_BottomOfTransferLoop:
        dec     cyExt
        jnz     short odb_TransferLoop

odb_exit:
        ReleaseScreen OEMDrawBits                ;allow cursor to do what it has to
        cCall   far_unexclude
        mov     ax,1                             ;always TRUE => no failure

odb_end:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = Setup8514Rect
;*
;* DESCRIPTION   = This routine sets the 8514's X, Y, DX, and DY registers to
;*                 the dimensions of the rectangle to be drawn and issues the
;*                 actual draw command.  Also, sets 8514's mode, and mix     
;*                 registers.  Checks that FIFO has enough room to accept    
;*                 incomming data.
;*
;*                 Registers Destroyed: AX,DX,flags
;*
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   Setup8514Rect, <NEAR, PUBLIC>
cBegin  <nogen>


;/*
;**  Since our source and destination have already been pre-clipped we do not
;**  have to worry about GP faults locally or coordinate wrap on the board.
;**  Therefore, we set up the board clip rectangle here so that it need not
;**  be done anywhere in the loop.
;** 
;**  In addition, we can assume that we are always writing to/from all planes,
;**  since PM doesn't seem to utilize plane enable as a concept, and we do not
;**  use it in the blt. Therefore, go ahead and enable all planes for reading
;**  and / or writing.
;*/

        WaitQ   6                       ; set up scissor rectangle
        Mov     Ax,xDst                 ; min left x
        Or      Ah,High XMIN_2DECODE
        .errnz  Low XMIN_2DECODE
        outwQ   XMIN                    ; x clip bounds is clipped rect bounds
        And     Ah,Not (High DECODE_FIELD)
        .errnz  Low DECODE_FIELD
        Add     Ax,cxExt                ; max right x
        Or      Ah,High XMAX_2DECODE
        .errnz  Low XMAX_2DECODE
        outwQ   XMAX
        outwQ   YMIN,YMIN_2DECODE       ; min y is always 0
        Mov     Ax,usBoardHeight        ; max y is max addressable y
        Or      Ah,High YMAX_2DECODE
        .errnz  Low YMAX_2DECODE
        outwQ   YMAX
        Mov     Al,0ffh                 ; all planes enabled for r/w
        outbQ   READ_ENABLE,Al
        outbQ   WRITE_ENABLE,Al

;/*
;** Before we start writing to the 8514 we want to make sure that the input
;** queue is empty, so that we don't need to check each time we write something
;*/

        WaitQ   7

;/*
;**  Set mode to host supplied data
;*/

        outwQ   MODE,MODE_2DECODE+MD_PS_VAR

;/*
;** Set the forground and background mix register to source-copy with host
;** supplied data
;*/

        mov     ax,FUNC_2OP_VAR+FUNC_S
        outwQ   FUNCTION_1
        outwQ   FUNCTION_0

;/*
;**  Set X and Y origin
;*/

        outwQ   X0,xDst
        mov     ax,yDst
        add     ax,cyExt
        dec     ax
        outwQ   Y0

;/*
;**  Set X and Y extents
;*/

        mov     ax,cxExt
        dec     ax
        outwQ   LX
        mov     ax,cyExt
        dec     ax
        outwQ   LY

CMDCOLOR        =       (\
                         CMD_C_HRECT+CMD_BYTEORDER+CMD_FV_VAR+\
                         CMD_DX+CMD_MA_ACCESS+CMD_PA_ONE+CMD_RW_W\
                        )

;/*
;** Make sure there is enough room for 1st data item on top of write command
;** befare issue proper write command
;*/

        WaitQ   2
        outwQ   CMD_FLAGS,CMDCOLOR

        ret

cEnd    <nogen>


;/***************************************************************************
;*
;* FUNCTION NAME = SegmentBoundaryProc24
;*
;* DESCRIPTION   = 
;*                                                                             
;*     This routine is called to handle segment boundary crossings in 24       
;*     bits/pixel DIBs.  Three different scenarious are possible:  
;*
;*     o  Segment boundary is crossed in the section to be skipped over (its
;*        size is specified by SrcX).  In this case the segment is updated       
;*        and the transfer function is called with modified wStartSkip.          
;*
;*     o  Segment boundary is crossed in the middle of the line segment to
;*        be displayed.  In this case the transfer function is called with       
;*        modified oCount and bRem, the segment is updated, and the transfer     
;*        function is called a second time with wStartSkip=0 and modified        
;*        oCount, bRem, and bStartRem.                                           
;*                                                                                    
;*     o  Segment boundary is crossed past the line segment to be displayed.
;*        In this case the transfer function is called with normal              
;*        parameters and the segment is updated afterwards.                     
;*
;*     Registers Destroyed: AX,CX,DX,flags
;*
;* INPUT         = AX = number of bytes in next segment (updated npCurSrcScan) 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   SegmentBoundaryProc24,<NEAR,PUBLIC>

cBegin  <nogen>

        mov     cx,ax
        mov     ax,cbSrcScan
        sub     ax,cx                             ;ax number of bytes left in old seg.
        jz      short CallAndUpdateSegment24
        mov     cx,ax
        cCall   SaveParameters
        sub     ax,Current.wStartSkip             ;NC->ax=#of bytes left to be displayed
        jc      short NonZeroStart24              ;CY->wStartSkip>#of bytes in old seg.
        mov     usOldSegmentPixelCount,ax
        mov     dx,ax
        mov     ax,cxExt                          ;make X ext into a byte extent
        shl     ax,1
        add     ax,cxExt
        cmp     dx,ax                             ;cxExt <= # of pixels left to do?
        jnb     short CallAndUpdateSegment24;yes, transfer them and update segment
        mov     ax,dx                             ;ax=# of bytes left to do
        xor     dx,dx                             ;prepare of division
        mov     cx,3
        div     cx                                ;ax:# of pixles, dx:remaining bytes
        mov     Current.oCount, ax                ;in old segment. put these values in
        mov     Current.bRem, dl                  ;oCount and bRem
        cCall   npfnTransferFunction              ;do rest of old (current) segment
        mov     ax,cxExt                          ;now commpute how many pixles are left
        shl     ax,1                              ;to blt out.
        add     ax,cxExt
        sub     ax,usOldSegmentPixelCount
        mov     dx,ax                             ;dx=ax=# of bytes in new segment
        mov     cx,3
        mov     al,Current.bRem                   ;if any partial pixels were started
        or      al,al
        jz      short bRemOkay
        mov     ah,cl                             ;save cl
        sub     cl,al                             ;now cl=1 or 2
        sub     dl,cl                             ;dx=dx-# of bytes left in partial pixel
        sbb     dh,ch                             ;ch=0
        mov     al,cl
        mov     cl,ah                             ;restore cl
bRemOkay:
        mov     Current.bStartRem, al             ;store # of bytes in partial pixel
        mov     ax,dx                             ;ax=adjusted # of bytes in new segment
        sub     dx,dx                             ;prepare for division
        mov     Current.wStartSkip, dx            ;no start skip at beginning of new seg.
        mov     Current.bRem, dl                  ;and no remainder either
        div     cx                                ;ax=number of pixels in new segment
        mov     Current.oCount, ax                ;dx better be zero at this point

UpdateSegmentAndCall24:
        cCall   NextSegmentDS                     ;update selector
        cCall   npfnTransferFunction              ;do remaining pixles in scanline
        cCall   RestoreParameters                 ;restore standard parameters
        jmp     short EndSegBndcr24               ;we're done

NonZeroStart24:
        sub     Current.wStartSkip, cx
        jmp     short UpdateSegmentAndCall24

CallAndUpdateSegment24:
        cCall   npfnTransferFunction
        cCall   NextSegmentDS

EndSegBndcr24:
        ret

cEnd    <nogen>


;/***************************************************************************
;*
;* FUNCTION NAME = SegmentBoundaryProc148
;*
;* DESCRIPTION   = 
;*     This routine is called to handle segment boundary crossings in 1, 4, or
;*     8 bits/pixel DIBs.  There are three different scenarious possible:     
;*
;*     o Segment boundary is crossed in the section to be skipped over (its
;*       size is specified by SrcX).  In this case the segment is updated and  
;*       the transfer function is called with modified wStartSkip.             
;*
;*     o Segment boundary is crossed in the middle of the line segment to be
;*       displayed.  In this case the transfer function is called with        
;*       modified oCount and bRem=0, the segment is updated, and the transfer 
;*       function is called a second time with wStartSkip=bStartRem=0 and     
;*       modified oCount and bRem.                                            
;*
;*     o Segment boundary is crossed past the line segment to be displayed.
;*       In this case the transfer function is called with normal parameters 
;*       and the segment is updated afterwards.                              
;*
;*     Registers Destroyed: AX,CX,DX,flags
;*
;* INPUT         = AX = number of bytes in next segment (updated npCurSrcScan) 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   SegmentBoundaryProc148,<NEAR,PUBLIC>

cBegin  <nogen>

        mov     cx,ax                             ; updated tmp source in cx
        mov     ax,cbSrcScan
        sub     ax,cx                             ; ax=#of bytes left to do in old segm.
        jz      short CallAndUpdateSegment
        mov     cx,ax                             ; keep # of bytes in old segment in cx
        call    SaveParameters
        push    bx
        mov     bl,iInnerCount
        sub     bh,bh
        mul     bx                                ; dx:ax #of pixels in old segment
        sub     ax,xSrc                           ; dx better be zero
        pop     bx
        jc      short NonZeroStart
        mov     usOldSegmentPixelCount,ax
        cmp     ax,cxExt
        jnb     short CallAndUpdateSegment
        sub     dx,dx                             ;now it's time to convert the pixel
        mov     cl,iInnerCount                    ;count in ax into a byte count so that
        sub     ch,ch                             ;ax=oCount
        div     cx
        cmp     Current.bStartRem,ch              ;at this point prev. Start up params
        jz      short NoPartialBytes              ;are still valid. dh better be zero
        dec     ax

NoPartialBytes:
        mov     Current.oCount,ax
        mov     Current.bRem,ch                   ;dh better be zero
        mov     dx,COLOR_1                        ;write directly to the board
        cCall   npfnTransferFunction              ;now do first half of this line
        mov     ax,cxExt
        sub     ax,usOldSegmentPixelCount
        mov     cl,iInnerCount
        sub     ch,ch
        sub     dx,dx
        div     cx
        mov     Current.oCount,ax
        mov     Current.bRem,dl
        sub     ax,ax
        mov     Current.wStartSkip,ax
        mov     Current.bStartRem,al

UpdateSegmentAndCall:
        call    NextSegmentDS
        mov     dx,COLOR_1                         ;write directly to the board
        cCall   npfnTransferFunction
        call    RestoreParameters
        jmp     short EndSegBndCr148

NonZeroStart:                                      ; cx: Bytes left to do in old segment
        sub     Current.wStartSkip, cx
        jmp     short UpdateSegmentAndCall

CallAndUpdateSegment:
        mov     dx, COLOR_1                        ;write directly to the board
        cCall   npfnTransferFunction
        call    NextSegmentDS

EndSegBndCr148:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = NextSegmentDS
;*
;* DESCRIPTION   = moves ds to the next segment (or selector in protected     
;*                 mode) and makes si 0
;*
;*                 Registers Destroyed: AX,CX,DX,flags
;*
;* INPUT         = NONE
;* OUTPUT        = DS:SI points to the 0th byte of the next segment 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   NextSegmentDS,<NEAR,PUBLIC>

cBegin  <nogen>

        mov     ax, ds                            ; get next segment with a little help
        add     ax, DOSHUGEINCR                   ; from kernel
        mov     ds, ax
        xor     si, si
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = SaveParameters
;*
;* DESCRIPTION   = 
;*
;*     In order to use the selected transfer function even in the case of     
;*     segment boundary crossings in the source bitmap, certain parameters    
;*     used by the transfer function must be modified and later restored.  All
;*     the parameters that might change are grouped together so that they can 
;*     be copied easily to a temporary buffer.                                
;*
;*     Registers Destroyed: AX,CX,DX,flags
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   SaveParameters,<NEAR,PUBLIC>

cBegin  <nogen>

        push    di
        push    si
        push    cx
        push    ax
        mov     ax, ss
        mov     es, ax
        assumes es,nothing
        lea     di, SaveParam
        lea     si, Current
        mov     cx, size ParameterBlock/2
        .errnz  (size ParameterBlock) and 1
rep     movs    word ptr es:[di],word ptr ss:[si]
        pop     ax
        pop     cx
        pop     si
        pop     di
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = RestoreParameters
;*
;* DESCRIPTION   = The complement of SaveParameters.  Does not alter any register. 
;*
;*                 Registers Destroyed: AX,CX,DX,flags
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   RestoreParameters,<NEAR,PUBLIC>

cBegin  <nogen>

        push    di
        push    si
        push    cx
        push    ax
        mov     ax, ss
        mov     es, ax
        assumes es,nothing
        lea     si, SaveParam
        lea     di, Current
        mov     cx, size ParameterBlock/2
        .errnz  (size ParameterBlock) and 1
rep     movs    word ptr es:[di],word ptr ss:[si]
        pop     ax
        pop     cx
        pop     si
        pop     di
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = Transfer24BitDIB
;*
;* DESCRIPTION   = 
;*
;*     This routine is used to copy transfer pixels from a device independent 
;*     bitmap to the screen.  Pixels are read from the source buffer,         
;*     tranlated into physical indices, and output directly to the screen.    
;*
;*     Registers Destroyed: AX,CX,DX,flags
;*
;*     Warning:
;*     It is the responsibility of the calling routine to check for segment
;*     boundary crossings.  The callers stack frame is assumed.
;*
;* INPUT         = DS:SI   points to the next source pel 
;*                 SS:BX   physical color table
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   Transfer24BitDIB,<NEAR,PUBLIC>

cBegin  <nogen>

        add     si,Current.wStartSkip             ;make pointer to actual pixels
        mov     cx,Current.oCount                 ;get outer loop count
        mov     al,Current.bStartRem              ;do we need to finish a partially
        or      al,al                             ;started pixel?
        jz      short Transfer24BitLoop_8         ;no, just do the real thing
        inc     cx                                ;need to loop once more than anticipated
        push    cx                                ;start the outer loop here
        mov     dl,bOldBlue                       ;always get old red
        cmp     al,2                              ;is this all we need to restore?
        je      short EntryGreen24_8              ;yes, enter the main loop
        mov     ah,bOldGreen                      ;need to get old Green
        jmp     short EntryBlue24_8               ;enter main loop

Transfer24BitLoop_8:
        push    cx
        lodsb
        mov     dl,al
EntryGreen24_8:
        lodsb
        mov     ah,al
EntryBlue24_8:
        lodsb                                     ;DL=blue, AH=green, AL=red
        xchg    al,dl                             ;DL=red,  AH=green, AL=blue
        cCall   drawbits_rgb_to_ipc
        mov     dx,COLOR_1
        out     dx,ax
        pop     cx
        loop    Transfer24BitLoop_8

        mov     dl,Current.bRem                   ;take care of remainder
        or      dl,dl                             ;do we need to start a partial pixel?
        jz      short Transfer24BitDIBEnd_8       ;no, get out now
        lodsb
        mov     bOldBlue,al
        cmp     dl,1
        jz      short Transfer24BitDIBEnd_8
        lodsb
        mov     bOldGreen,al

Transfer24BitDIBEnd_8:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = Transfer148BitDIB
;*
;* DESCRIPTION   = 
;*
;*     This routine is used to copy transfer pixels from a device independent 
;*     bitmap to the screen.  Pixels are read from the source buffer,         
;*     tranlated into physical indices, and output directly to the screen.    
;*
;*     Registers Destroyed: AX,CX,DX,flags
;*
;*     Warning:
;*     It is the responsibility of the calling routine to check for segment 
;*     boundary crossings.  The callers stack frame is assumed.
;*
;* INPUT         = DS:SI   points to the next source pel 
;*                 SS:BX   physical color table
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   Transfer148BitDIB,<NEAR,PUBLIC>

cBegin  <nogen>

        mov     ax,Current.wStartSkip
        add     si,ax
        mov     al,Current.bStartRem
        or      al,al
        jz      short StartByteAlligned
        mov     ah,iInnerCount
        sub     ah,al
        lodsb
        mov     cl,bShiftCount
        jz      short SomethingWeirdHappend   ; ah should never be zero at this point

StartSkipShiftLoop:
        rol     al, cl                        ; in this byte
        dec     ah
        jnz     short StartSkipShiftLoop

SomethingWeirdHappend:
        mov     ch, Current.bStartRem
        mov     ah, al

StartLoop:
        rol     ah, cl
        mov     al, ah
        and     ax, di
        xlatb   gs:[bx]
        out     dx,ax
        dec     ch
        jnz     short StartLoop

StartByteAlligned:
        mov     cx, Current.oCount
        jcxz    oLoopEnd                      ; if cx=0 skip outer loop entirely

oLoop148:
        push    cx                            ;this is the main part if the transfer
        mov     cl, bShiftCount               ;process
        mov     ch, iInnerCount
        lodsb
        mov     ah, al

iLoop148:
        rol     ah, cl
        mov     al, ah
        and     ax, di
        xlatb   gs:[bx]
        out     dx,ax
        dec     ch
        jnz     short iLoop148
        pop     cx
        loop    oLoop148

oLoopEnd:
        mov     ch, Current.bRem
        or      ch, ch
        jz      short BypassRem148
        mov     cl, bShiftCount
        lodsb
        mov     ah, al

rLoop148:
        rol     ah, cl
        mov     al, ah
        and     ax, di
        xlatb   gs:[bx]
        out     dx,ax
        dec     ch
        jnz     short rLoop148

BypassRem148:
        ret

cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = drawbits_rgb_to_ipc
;*
;* DESCRIPTION   = 
;*
;*     This routine converts an RGB value to the correct physical index to    
;*     use.  If there is a palette in the DC, it validates the index (maps to 
;*     black if invalid).                                                     
;*
;*     Registers Destroyed: AX,CX,DX,flags
;*
;* INPUT         = DL:AH:AL = RGB 
;* OUTPUT        = AL = ipc       
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   drawbits_rgb_to_ipc,<NEAR,PUBLIC>,<>
cBegin
        xor     dh,dh                             ; no special bits
        test    fbPal,ODB_PALETTE
        jnz     short dbrti_custom_palette
        cCall   rgb_to_ipc                        ; convert to internal physical color
        jmp     dbrti_got_ipc

dbrti_custom_palette:
        test    fbPal,ODB_PAL_INDICES
        jnz     short dbrti_pal_indices
        farPtr  myrgb,dx,ax
        cCall   far_rgb_to_ipc_with_pal,<myrgb,lpClrTab>
        jmp     dbrti_got_pal_ipc

dbrti_return_zero:
        xor     ax,ax
        jmp     short dbrti_restore_stack

dbrti_pal_indices:
        push    ds                           
        push    si                           
        lds     si,lpClrTab
        assumes ds,nothing
        ror     eax,16
        xchg    ax,dx
        ror     eax,16
        index?  dbrti_return_zero,ds,si,SIZE_HW_PAL-1
dbrti_restore_stack:
        pop     si
        pop     ds
        assumes ds,nothing

dbrti_got_pal_ipc:
        xor     ah,ah                            ;don't want ipc accelerator bits
        push    ds                               ;!!! more segment loads
        push    si
        lds     si,lpClrTab
        assumes ds,nothing
        xchg    ax,bx
        palOff  bx
        mov     al,[si+bx].palseg_apalclr.palclr_bCur
        pop     si
        pop     ds
        assumes ds,nothing

dbrti_got_ipc:
cEnd

sEnd    Code

        public  odb_get_bmi
        public  odb_new_header
        public  odb_have_info
        public  odb_init_24_bpp
        public  odb_Not24BitDIB
        public  odb_AllignmentLoop
        public  odb_AllignmentLoopEnd
        public  odb_OuterCountOkay
        public  odb_TransferSelected
        public  odb_cursor_exclude
        public  odb_set_up_screen
        public  odb_calc_src_offset
        public  odb_TransferLoop
        public  odb_NoSegmentCrossing
        public  odb_BottomOfTransferLoop
        public  odb_exit

end
