;*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 = CSDEVSUP.ASM
;*
;* DESCRIPTIVE NAME = 
;*
;*
;* VERSION      V2.0
;*
;* DATE         04/17/87
;*
;* DESCRIPTION  This module contains the CharString functions which output the  
;*              character bits to the display.                                  
;*              
;* FUNCTIONS    build_to_screen
;*              columns_to_screen
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   04/17/87                     Author:  Walt Moore [waltm]
;*   05/24/88                     Mitchell McLain [gssc!mmm]
;*                                Added support for ABC-spaced text.
;*   05/09/88                     Mitchell McLain [gssc!mmm]
;*                                Added support for a width vector.
;*****************************************************************************/

        .xlist
        include cmacros.inc
INCL_GRE_CLIP           equ     1
INCL_FONTFILEFORMAT     equ     1
        include pmgre.inc
        include driver.inc
        include 8514.inc
        include 8514mem.inc
        include strblt8.inc
        include fontseg.inc
        .list


sBegin  Code
        assumes cs,Code
        assumes ss,ss_variables

        externNP    prepare_for_overlap

define_frame strblt_frame               ;Define strblt's frame
cBegin  <nogen>
cEnd    <nogen>

        page
;/***************************************************************************
;*
;* FUNCTION NAME = build_to_screen
;*
;* DESCRIPTION   = This is the special case for displaying text in a font that
;*                 could not be cached in offscreen memory.
;*
;*                 Registers Preserved:
;*                       BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;* INPUT         = stack frame as per strblt 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        public  build_to_screen         ; for debugging only
build_to_screen proc    near

        mov     al,accel                ;Save the actual state of the
        mov     bl,al                   ;  IS_OPAQUE flag since the
        and     al,IS_OPAQUE            ;  prepare_for_overlap code may
        or      wc_flags,al             ;  alter it
        mov     ah,excel                ;Only set text visible once a string
        and     ah,not TEXT_VISIBLE     ; is actually displayed
        mov     excel,ah

        test    bl,IS_OPAQUE            ;If transparent mode, then no
        jz      @F                      ;  special work is required
        test    bl,(HAVE_WIDTH_VECT or HAVE_CHAR_EXTRA) ; No extra work if
        jz      @F                      ;  no width vector and no char extra.
        call    prepare_for_overlap     ;Massive preprocessing required

@@:


;/*
;**     The first order of business is to determine whether or not there
;**     is a width vector to deal with.  If so, make a local copy on the
;**     stack, so it's available in the display loops below.
;*/

        mov     al,accel
        test    al,HAVE_WIDTH_VECT
        jz      @F

        lds     si,lp_dx                ; DS:SI -> width vector
        assumes ds,nothing

        mov     bx,ss
        mov     es,bx                   ; SS -> stack
        assumes es,nothing

        mov     cx,count                ; Number of entries in the width vector
        sub     sp,cx                   ; Make room for local copy of the
        sub     sp,cx                   ;   width vector (in bytes).
        mov     bx,cx                   ; Save count
        mov     di,sp                   ; ES:DI -> local copy of width vector
        cld
rep     movsw                           ; Copy width vector

@@:

;/*
;**     Here's how it's going to be done -- at least for the first pass
;**     at this stuff:
;**
;**         1. Set the hardware clip rectangle.
;**         2. Set the hardware colors for text and background.
;**         3. Set the second operand source plus background and
;**            foreground writing modes.
;**         4. Loop through the text string, using the horizontal
;**            rectangle hardware command to display text from the host
;**            character bit data.
;**
;**     Actually, only the XMIN, YMIN and YMAX coordinates of the
;**     hardware clip rectangle are set right now.  The XMAX coordinate
;**     is stepped along the character string.  For each character
;**     output, the right edge of the character box becomes the new
;**     XMAX of the clip rectangle.  By setting the right edge of the
;**     clip rectangle this way, a great deal of painful bitwise
;**     overlap fuss is avoided and pushed off to the hardware.
;**
;**     The reason for all this is that the 8514 always aligns the
;**     first bit of its pattern to the first nibble boundary (even
;**     multiple of 4) that is less than or equal to the destination
;**     X coordinate.  This means that if the destination is not on
;**     a nibble boundary, then the pattern must be correctly aligned
;**     with it by using bitwise shifting and rotation.
;**
;**     If the destination X coordinate is not on a nibble boundary,
;**     then three OUT instructions must be executed in order to display
;**     all 8 bits of a given column of character data; otherwise, two
;**     OUT instructions will suffice.  The 8514 is set to byte mode in
;**     order to avoid writing too many pixels when the destination X
;**     coordinate is not nibble aligned.  Remember, the 8514 will write
;**     only UP TO 4 pattern bits per OUT instruction when in byte mode.
;**
;**     For example, assume the destination X coordinate is 1 bit to the
;**     right of some nibble boundary.  The column data is displayed as
;**     follows:
;**
;**     Nibble boundary-+ +-Destination X coordinate
;**                     | |      +-Another nibble boundary
;**                     v v      v       +-And another
;**                     . . . .  . . . .  . . . .
;**                       1 0 1  1 0 0 1  0         1 row of column data
;**
;**     In order to output the bits to the 8514, they must be broken
;**     into chunks of up to 4 bits each and correctly aligned.  The
;**     above pattern will be broken into the following chunks:
;**
;**                  x 1 0 1  1 0 0 1  0 x x x    1 row of column data
;**
;**     The first chunk, also called the lefthand side, consists of one
;**     don't-care bit followed by three pattern bits.  The second chunk
;**     consists of 4 pattern bits.  And the third chunk consists of 1
;**     pattern bit followed by 3 don't-care bits.
;**
;**     The 8514 knows the destination X coordinate as well as the fact
;**     that each column of data is 8 bits (pixels) wide.  When the
;**     lefthand side of the dissected pattern is sent to the board, it
;**     will align the don't-care bit to the nibble boundary indicated
;**     and treat the 1 0 1 bits as foreground, background and
;**     foreground, respectively.
;**
;**     The second chunk, also called the middle bits, (1 0 0 1) will be
;**     treated as foreground, background, background and foreground
;**     bits, respectively.  It can be sent out whole, because it has
;**     been arranged so that it's first bit aligns correctly with a
;**     nibble boundary.
;**
;**     The third chunk, also called the righthand side, (0 x x x) will
;**     also be aligned to a nibble boundary, but because the 8514 knows
;**     the column is 8 bits (pixels) wide, the last three bits of the
;**     chunk are ignored. The first bit is treated as a background bit.
;**
;**     If, by chance, the destination X coordinate of the character is
;**     nibble aligned, then only two chunks, a lefthand side and a
;**     righthand side, are required (4 bits per chunk) in order to
;**     display the data column, making the job somewhat easier.
;**
;**     It should be noted that displaying character data
;**     column-by-column is vastly less complicated than displaying it
;**     row-by-row.  Displaying row-by-row results in what is
;**     unaffectionately known as "pipelining." Pipelining requires
;**     next-byte prefetching, masking and other related fuss that is
;**     avoided by displaying column-by-column.
;*/

;/*
;**  Set the hardware clip rectangle, using the clip rectangle on the stack
;** 
;**  The text clip rectangle is different than the normal PM clip rectangle
;**  in terms of which edges are inclusive and which are exclusive.  In PM,
;**  the left and bottom edges are inclusive and the top and right edges
;**  are exclusive.  The text path, however, is based on         code, and
;**  in         the top and left edges are inclusive and the bottom and
;**  right edges are exclusive.  Set up the hardware clip rectangle with
;**  that in mind.
;*/

        WaitQ   6                       ; Wait for an empty queue

        mov     ax,clip.rcs_pts1.pts_x  ; Left edge (inclusive)
        or      ax,XMIN_2DECODE
        .errnz   XMIN_2DECODE and 0000111111111111b
        outwQ   XMIN

        mov     ax,clip.rcs_pts1.pts_y  ; Top edge (inclusive)
        or      ax,YMIN_2DECODE
        .errnz   YMIN_2DECODE and 0000111111111111b
        outwQ   YMIN

;/*
;**     Don't worry about XMAX.  That will be stepped along the text string as
;**     each character is output.
;*/

        mov     ax,clip.rcs_pts2.pts_y
        dec     ax                      ; Bottom edge (exclusive)
        or      ax,YMAX_2DECODE
        .errnz   YMAX_2DECODE and 0000111111111111b
        outwQ   YMAX

;/*
;**     Set the text (foreground) and background colors, using the color
;**     information on the local frame.
;*/

        xor     ah,ah                   ; Let's avoid any extraneous stuff here
        mov     al,byte ptr colors[BACKGROUND]
        outwQ   COLOR_0                 ; Set background color
        mov     al,byte ptr colors[FOREGROUND]
        outwQ   COLOR_1                 ; Set foreground color


;/*
;**     Set the hardware writing modes.
;**
;**         BG = opaque or transparent, depending on "accel" IS_OPAQUE bit
;**         FG = opaque, XOR or OR, depending on "accel" IS_XOR_TEXT and
;**              IS_OR_TEXT bits
;*/

        WaitQ   7                       ; Wait for room on the input queue

        mov     bl,accel

;/*
;**     Background
;*/

        mov     al,FUNC_S               ; Assume opaque background
        shr     bl,1                    ; Opaque?
        .errnz  IS_OPAQUE shr 1
        jc      @F                      ; Yes, it's opaque
        mov     al,FUNC_D               ; Force transparent background
@@:     or      al,FUNC_2OP_COL0        ; BG color source is COLOR 0
        .errnz  FUNC_2OP_COL0 and 011111b
        outwQ   FUNCTION_0              ; Background mode to 8514

;/*
;**     Foreground
;*/

        mov     al,FUNC_S_XOR_D         ; Assume XOR foreground
        shr     bl,1                    ; XOR?
        .errnz  IS_XOR_TEXT shr 2
        jc      @F                      ; Yes
        mov     al,FUNC_S_OR_D          ; Assume OR foreground
        shr     bl,1                    ; OR?
        .errnz  IS_OR_TEXT shr 3
        jc      @F                      ; Yes
        mov     al,FUNC_S               ; Force opaque foreground
@@:     or      al,FUNC_2OP_COL1        ; FG color source is COLOR_1
        .errnz  FUNC_2OP_COL1 and 011111b
        outwQ   FUNCTION_1


;/*
;**     Other hardware setup:
;**
;**         Enable all planes for writing
;**         Set pattern source to be data from the host
;**         Set the dimensions of the character data columns
;*/

        outwQ   WRITE_ENABLE,0ffh       ; Enable all planes for writing

        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR);Pattern source variable data

        mov     ax,7                    ; Data columns are 8 wide...
        outwQ   LX                      ;   ...8514 wants it minus 1

        mov     ax,lfd.font_height
        dec     ax                      ; Board wants 1 less than height
        or      ax,LY_2DECODE           ; Bits for secondary decode command
        outwQ   LY                      ; Inform board of height

;/*
;**     The character generation code displays each character in
;**     rectangles 8 bits wide by lfd.font_height rows high.  This
;**     conforms to the way the character data is stored in host memory
;**     and turns out to be a fairly straightforward way to get the bits
;**     to the board.
;**
;**     Here's what the board will need to know for each character of
;**     the text string to be displayed:
;**
;**         (X0,Y0) - destination coordinates for the character
;**         LX,LY   - the dimensions of each rectangle of each character
;**                   cell (this is a constant value and has already
;**                   been sent to the board)
;**         XMAX    - the character extent used as the current clip XMAX
;**         The command indicating what the board should do:
;**             Horizontal Rectangle
;**             Using byte mode
;**             Using variable pattern data
;**             Increment X and Y as command proceeds
;**             Write up to four pixels at-a-time
;**             Enable write access to the planes
;*/

        lds     si,lp_string
        assumes ds,nothing

        mov     es,selFont
        assumes es,FontSeg

        test    accel,ABC_FONT          ; ABC-spaced font?
        jz      bts_not_abc_font        ; No

        jmp     bts_abc_character_display ; Off to handle ABC-spaced font

bts_not_abc_font:
        mov     cx,count                ; Draw this many characters

bts_character_display_loop:
        WaitQ   8                       ; Wait for room in the 8514 queue
        lodsw                           ; Fetch code point
        add     ax,ax                   ; * 2
        mov     bx,ax
        add     ax,ax                   ; * 4
        add     bx,ax                   ; * 6
        .errnz  (size FONT_ENTRIES) - 6

        mov     ax,x                    ; AX = destination X
        and     ax,XY_SIGNIFICANT       ; Mask off insignificant bits for 8514
        outwQ   X0                      ; Give board destination X

ifdef   FIREWALLS
        cmp     ax,x                    ; Assume outwQ leaves AX = X
        je      @F
        rip     text,<outwQ trashes AX unexpectedly.>
@@:
endif

;/*
;**       Set this character's max X clip edge
;*/

        mov     di,ax                   ; Save destination X for the moment
        add     ax,fsCharOffset[bx].fe_width ; Add in character's width
        cmp     ax,di                   ; Zero width?
        je      bts_one_less_char       ; Yes.
        mov     dx,clip.rcs_pts2.pts_x
        cmp     ax,dx                   ; Right of character beyond max clip X?
        jl      @F                      ; No, use right edge of character
        mov     ax,dx                   ; Use max clip X minus 1. The clip
        dec     ax                      ;   rectangle is exclusive on the right.
@@:
        or      ax,XMAX_2DECODE         ; Add in 8514 decode bits
        .errnz  XMAX_2DECODE and 0000111111111111b
        outwQ   XMAX                    ; Set hardware clip XMAX
        mov     ax,di                   ; Restore destination X

;/*
;**       Calculate the next character's position
;*/

        mov     dx,fsCharOffset[bx].fe_width ; Fetch character's width again
        mov     di,dx                   ; Safe keeping...

        test    accel,HAVE_WIDTH_VECT
        jz      @F
        pop     dx                      ; Character's width vector entry
@@:
        push    cx                      ; Save count, freeing up a register
        mov     cx,ax                   ; Save current X
        add     ax,dx                   ; Add in character width
        add     ax,char_extra           ; Add in extra character spacing,
        mov     x,ax                    ;   giving next character position

;/*
;** Calculate remaining information needed on a per-character basis
;*/

        push    si                      ; Save next codepoint offset
        mov     si,fsCharOffset[bx].fe_dBits.lo ; ES:SI -> character data

        and     cx,3                    ; CX = phase shift count
        mov     bx,di                   ; Set up to calculate columns of data
        add     bx,7                    ; Round up to next full column
        shr     bx,3                    ; Number of columns in character data
        jz      @F                      ; Jump if no data to display

        call    columns_to_screen       ; Display the character

@@:
        pop     si                      ; Restore codepoint offset
        pop     cx                      ; Restore character count

bts_one_less_char:
        dec     cx                      ; One less character to worry about
        jz      @F
        jmp     bts_character_display_loop

@@:
        jmp     bts_return              ; Done; leave.

;/*
;**       Display ABC-spaced text
;*/

        public  bts_abc_character_display ; Debugging
bts_abc_character_display:
        mov     cx,count                ; Draw this many characters

bts_abc_character_display_loop:
        WaitQ   8                       ; Wait for room in the 8514 queue
        lodsw                           ; Fetch code point
        add     ax,ax                   ; * 2
        mov     bx,ax
        add     ax,ax                   ; * 4
        add     ax,ax                   ; * 8
        add     bx,ax                   ; * 10
        .errnz  (size ABC_FONT_ENTRIES) - 10

        mov     ax,fsCharOffset[bx].abc_a_space
        add     ax,x
        mov     di,ax                   ; Save destination X for the moment
        and     ax,XY_SIGNIFICANT       ; Mask off insignificant bits
        outwQ   X0                      ; Give board destination X

;/*
;**       Set this character's max X clip edge
;*/

        mov     ax,di                   ; Restore unmasked destination X
        add     ax,fsCharOffset[bx].abc_b_space ; Add in character's width
        cmp     ax,di                   ; Zero width?
        je      bts_abc_one_less_char   ; Yes.
        mov     dx,clip.rcs_pts2.pts_x
        cmp     ax,dx                   ; Right of character beyond max clip X?
        jl      @F                      ; No, use right edge of character
        mov     ax,dx                   ; Use max clip X minus 1. The clip
        dec     ax                      ;   rectangle is exclusive on the right.
@@:
        or      ax,XMAX_2DECODE         ; Add in 8514 decode bits
        .errnz  XMAX_2DECODE and 0000111111111111b
        outwQ   XMAX                    ; Set hardware clip XMAX
        mov     ax,di                   ; Restore destination X

;/*
;**       Calculate the next character's position
;*/

        mov     dx,fsCharOffset[bx].abc_b_space ; Fetch character's width again
        mov     di,dx                   ; Safe keeping...

        test    accel,HAVE_WIDTH_VECT
        jz      @F
        pop     dx                      ; Character's width vector entry
@@:
        push    cx                      ; Save count, freeing up a register
        mov     cx,ax                   ; Save current destination X
        add     ax,dx                   ; Add in character width
        add     ax,fsCharOffset[bx].abc_c_space ; Add in "C" spacing
        add     ax,char_extra           ; Add in extra character spacing,
        mov     x,ax                    ;   giving next character position

;/*
;** Calculate remaining information needed on a per-character basis
;*/

        push    si                      ; Save next codepoint offset
        mov     si,fsCharOffset[bx].abc_fe_dBits.lo ; ES:SI -> character data

        and     cx,3                    ; CX = phase shift count
        mov     bx,di                   ; Set up to calculate columns of data
        add     bx,7                    ; Round up to next full column
        shr     bx,3                    ; Number of columns in character data
        jz      @F                      ; Jump if no data to display

        call    columns_to_screen       ; Display the character

@@:
        pop     si                      ; Restore codepoint offset
        pop     cx                      ; Restore character count

bts_abc_one_less_char:
        dec     cx                      ; One less character to worry about
        jz      bts_return              ; Outta here if no more characters
        jmp     bts_abc_character_display_loop

        assumes es,nothing
        assumes ds,nothing

bts_return:
        or      excel,TEXT_VISIBLE      ;Show something was displayed

        mov     al,wc_flags
        test    al,WC_SET_LR            ;If we stepped backwards, we'll
        jz      bts_really_return       ;  have to restore the real lhs
        mov     bx,wc_opaque_lhs        ;  and rhs in case we have an
        mov     text_bbox.rcs_pts1.pts_x,bx ;  opaque rectangle.
        mov     bx,wc_opaque_rhs
        mov     text_bbox.rcs_pts2.pts_x,bx

bts_really_return:
        and     al,IS_OPAQUE            ;Restore IS_OPAQUE incase prepare_for-
        or      accel,al                ;  overlap code cleared it, else the
                                        ;  opaque rectangle may overwrite our
                                        ;  text.
        ret
build_to_screen endp

;/***************************************************************************
;*
;* FUNCTION NAME = columns_to_screen
;*
;* DESCRIPTION   = Display the columns of bit patterns that define a character 
;*
;*                 Registers Preserved:
;*                       BX,CX,SI,BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,DX,DI
;*
;* INPUT         = ES:SI   ->  top of character data column        
;*                 BX      =   Number of columns in character data
;*                 CL      =   Phase shift count
;*                 stack frame as per strblt
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        public  columns_to_screen        ; For debugging
columns_to_screen    proc    near

cts_character_column_loop:


;/*
;** Set hardware destination for this column.  Hardware automatically updates
;** X after every column is output.
;*/

        mov     ax,y                    ; AX = destination Y
        and     ax,XY_SIGNIFICANT       ; Mask of insignificant bits
        outwQ   Y0                      ; Give board destination Y
        outwQ   CMD_FLAGS,<CMD_C_HRECT+CMD_WORD+CMD_FV_VAR+CMD_DY+CMD_DX+\
                CMD_MA_ACCESS+CMD_PA_FOUR+CMD_RW_W>
        mov     di,lfd.font_height      ; Number of rows in character data

cts_character_row_loop:
        xor     ah,ah                   ; Clear for right hand pattern bits
        lods    es:byte ptr[si]         ; Fetch P0|P1
        ror     ax,cl                   ; Align with destination; save rh bits
        ror     al,3                    ; now aligned P1|P0 (P0 in hw position)

;/*
;** Output the left hand bits to the 8514
;*/

        outbQ   COLOR_0                 ; Output P0

;/*
;** Output the middle bits to the 8514
;*/

        rol     al,4                    ; Middle bits to hw position
        outbQ   COLOR_0                 ; Output the middle bits

        jcxz    @F                      ; Done if phase shift is 0

;/*
;** Output the right hand bits to the 8514
;*/

        mov     al,ah                   ; Right hand bits to left side of AL
        shr     al,3                    ; Right hand bits to hardware position
        outbQ   COLOR_0                 ; Output right hand bits

@@:     dec     di                      ; One less row to worry about
        jnz     cts_character_row_loop

        mov     dx,X0
        in      ax,dx                   ; Get new X (8514 tracks X0)
        inc     ax                      ; Increment to next column on the screen
        out     dx,ax                   ; Tell the 8514 about it
        dec     bx                      ; One less column to worry about
        jnz     cts_character_column_loop

        ret
columns_to_screen    endp

sEnd    Code
        end
