Annotation of ntddk/src/video/displays/vga256/i386/fasttext.asm, revision 1.1.1.1

1.1       root        1: ;---------------------------Module-Header------------------------------;
                      2: ; Module Name: fasttext.asm
                      3: ;
                      4: ; Copyright (c) 1992 Microsoft Corporation
                      5: ;-----------------------------------------------------------------------;
                      6: ;-----------------------------------------------------------------------;
                      7: ; BOOL vFastText(PDEV * ppdev, GLYPHPOS * pGlyphPos, ULONG ulGlyphCount,
                      8: ;                PBYTE pTempBuffer, ULONG ulBufDelta, ULONG ulCharInc,
                      9: ;                RECTL * prclText, RECTL * prclOpaque, INT iFgColor,
                     10: ;                INT iBgColor, ULONG fDrawFlags);
                     11: ; ppdev -
                     12: ; pGlyphPos -
                     13: ; ulGlyphCount - # of glyphs to draw. Must never be 0.
                     14: ; pTempBuffer -
                     15: ; ulBufDelta - logical width of temp buffer in bytes. This value *must* be the
                     16: ;               same number of bytes spanned by prclText; it is assumed that
                     17: ;               scans in the temp buffer are contiguous
                     18: ; ulCharInc -
                     19: ; prclText -
                     20: ; prclOpaque -
                     21: ; iFgColor -
                     22: ; iBgColor -
                     23: ; fDrawFlags -
                     24: ;
                     25: ; Performs accelerated proportional text drawing.
                     26: ;
                     27: ;-----------------------------------------------------------------------;
                     28: ;
                     29: ; Note: The general opaque text back-end currently assumes that it will
                     30: ; never receive a text string with a bounding box that does not span at
                     31: ; least one quadpixel (the four pixels at a VGA screen address).
                     32: ;
                     33: ;-----------------------------------------------------------------------;
                     34: ;
                     35: ; Note: The term "quadpixel" means a four-pixel set stored across all
                     36: ; four planes of VGA memory in planar high-color mode. Quadpixels map to
                     37: ; nibbles in the temp buffer in which text is assembled, where nibbles
                     38: ; are always bits 4-7 or 0-3.
                     39: ;
                     40: ;-----------------------------------------------------------------------;
                     41: ;
                     42: ; Note: The direction flag is *not* explicitly set or cleared.
                     43: ;
                     44: ;-----------------------------------------------------------------------;
                     45: ;
                     46: ; Note: Assumes the text rectangle has a positive height and width. Will
                     47: ; not work properly if this is not the case.
                     48: ;
                     49: ;-----------------------------------------------------------------------;
                     50: ;
                     51: ; Set LOOP_UNROLL_SHIFT to the log2 of the number of times you want to unroll
                     52: ; loops in this module that are implemented with the unrolling macros. For
                     53: ; example, LOOP_UNROLL_SHIFT of 3 yields 2**3 = 8 times unrolling. This is
                     54: ; the only thing you need to change to control unrolling.
                     55: 
                     56: LOOP_UNROLL_SHIFT equ 2
                     57: 
                     58: ;-----------------------------------------------------------------------;
                     59: 
                     60:         comment $
                     61: 
                     62: The overall approach of this module is to draw the text into a system
                     63: memory buffer, then copy the buffer to the screen a word at a time
                     64: using write mode 2 and clever use of the VGA hardware so that no OUTs
                     65: and a minimum of display memory reads are required. The clever use is
                     66: setting the ALUs to XOR, the latches to the background color, and the
                     67: write mode to 2, so each nibble in bits 0-3 written by the CPU turns
                     68: into 0 or 0ffh for that plane. Then the Bit Mask is set to fg ^ bg,
                     69: so that common bits between the fg and bg are preserved, while non-
                     70: common bits are either preserved (=bg color) by a 0->000h bit for
                     71: that plane, or flipped (=fg color) by a 1->0ffh bit for that plane. The
                     72: Map Mask is used to clip edges; no read before write is required. Note
                     73: that bits 0-3 must be reversed to match the order of pixels in planes
                     74: 0-3. Note also that we write a whole word, containing two nibbles in
                     75: bits 0-3 of each byte, at once, to draw 8 pixels per write.
                     76: 
                     77:         commend $
                     78: 
                     79:         .386
                     80: 
                     81: ifndef  DOS_PLATFORM
                     82:         .model  small,c
                     83: else
                     84: ifdef   STD_CALL
                     85:         .model  small,c
                     86: else
                     87:         .model  small,pascal
                     88: endif;  STD_CALL
                     89: endif;  DOS_PLATFORM
                     90: 
                     91:         assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
                     92:         assume fs:nothing,gs:nothing
                     93: 
                     94:         .xlist
                     95:         include stdcall.inc             ;calling convention cmacros
                     96:         include i386\strucs.inc
                     97:         include i386\driver.inc
                     98:         include i386\egavga.inc
                     99:         include i386\unroll.inc
                    100: 
                    101:         .list
                    102: 
                    103: ;-----------------------------------------------------------------------;
                    104: 
                    105:         .data
                    106: 
                    107: ;-----------------------------------------------------------------------;
                    108: ; Tables used to branch into glyph-drawing optimizations.
                    109: ;
                    110: ; Handles narrow (1-4 bytes wide) glyph drawing, for case where initial byte
                    111: ; should be MOVed even if it's not aligned (intended for use in drawing the
                    112: ; first glyph in a string). Table format is:
                    113: ;  Bits 3-2: dest width
                    114: ;  Bit   1 : 1 if don't need last source byte, 0 if do need last source byte
                    115: ;  Bit   0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
                    116:         align   4
                    117: MovInitialTableNarrow   label   dword
                    118:         dd      draw_prop_done                     ;0 wide
                    119:         dd      draw_prop_done                     ;0 wide
                    120:         dd      draw_prop_done                     ;0 wide
                    121:         dd      draw_prop_done                     ;0 wide
                    122:         dd      mov_first_1_wide_rotated_need_last ;nonalign, 1 wide, need last
                    123:         dd      mov_first_1_wide_unrotated         ;aligned, 1 wide
                    124:         dd      mov_first_1_wide_rotated_no_last   ;nonalign, 1 wide, no last
                    125:         dd      mov_first_1_wide_unrotated         ;aligned, 1 wide
                    126:         dd      mov_first_2_wide_rotated_need_last ;nonalign, 2 wide, need last
                    127:         dd      mov_first_2_wide_unrotated         ;aligned, 2 wide
                    128:         dd      mov_first_2_wide_rotated_no_last   ;nonalign, 2 wide, no last
                    129:         dd      mov_first_2_wide_unrotated         ;aligned, 2 wide
                    130:         dd      mov_first_3_wide_rotated_need_last ;nonalign, 3 wide, need last
                    131:         dd      mov_first_3_wide_unrotated         ;aligned, 3 wide
                    132:         dd      mov_first_3_wide_rotated_no_last   ;nonalign, 3 wide, no last
                    133:         dd      mov_first_3_wide_unrotated         ;aligned, 3 wide
                    134:         dd      mov_first_4_wide_rotated_need_last ;nonalign, 4 wide, need last
                    135:         dd      mov_first_4_wide_unrotated         ;aligned, 4 wide
                    136:         dd      mov_first_4_wide_rotated_no_last   ;nonalign, 4 wide, no last
                    137:         dd      mov_first_4_wide_unrotated         ;aligned, 4 wide
                    138: 
                    139: ; Handles narrow (1-4 bytes wide) glyph drawing, for case where initial byte
                    140: ; ORed if it's not aligned (intended for use in drawing all but the first glyph
                    141: ; in a string). Table format is:
                    142: ;  Bits 3-2: dest width
                    143: ;  Bit   1 : 1 if don't need last source byte, 0 if do need last source byte
                    144: ;  Bit   0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
                    145:         align   4
                    146: OrInitialTableNarrow    label   dword
                    147:         dd      draw_prop_done                     ;0 wide
                    148:         dd      draw_prop_done                     ;0 wide
                    149:         dd      draw_prop_done                     ;0 wide
                    150:         dd      draw_prop_done                     ;0 wide
                    151:         dd      or_first_1_wide_rotated_need_last  ;nonalign, 1 wide, need last
                    152:         dd      mov_first_1_wide_unrotated         ;aligned, 1 wide
                    153:         dd      or_first_1_wide_rotated_no_last    ;nonalign, 1 wide, no last
                    154:         dd      mov_first_1_wide_unrotated         ;aligned, 1 wide
                    155:         dd      or_first_2_wide_rotated_need_last  ;nonalign, 2 wide, need last
                    156:         dd      mov_first_2_wide_unrotated         ;aligned, 2 wide
                    157:         dd      or_first_2_wide_rotated_no_last    ;nonalign, 2 wide, no last
                    158:         dd      mov_first_2_wide_unrotated         ;aligned, 2 wide
                    159:         dd      or_first_3_wide_rotated_need_last  ;nonalign, 3 wide, need last
                    160:         dd      mov_first_3_wide_unrotated         ;aligned, 3 wide
                    161:         dd      or_first_3_wide_rotated_no_last    ;nonalign, 3 wide, no last
                    162:         dd      mov_first_3_wide_unrotated         ;aligned, 3 wide
                    163:         dd      or_first_4_wide_rotated_need_last  ;nonalign, 4 wide, need last
                    164:         dd      mov_first_4_wide_unrotated         ;aligned, 4 wide
                    165:         dd      or_first_4_wide_rotated_no_last    ;nonalign, 4 wide, no last
                    166:         dd      mov_first_4_wide_unrotated         ;aligned, 4 wide
                    167: 
                    168: ; Handles narrow (1-4 bytes wide) glyph drawing, for case where all bytes
                    169: ; should be ORed (intended for use in drawing potentially overlapping glyphs).
                    170: ; Table format is:
                    171: ;  Bits 3-2: dest width
                    172: ;  Bit   1 : 1 if don't need last source byte, 0 if do need last source byte
                    173: ;  Bit   0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
                    174:         align   4
                    175: OrAllTableNarrow        label   dword
                    176:         dd      draw_prop_done                     ;0 wide
                    177:         dd      draw_prop_done                     ;0 wide
                    178:         dd      draw_prop_done                     ;0 wide
                    179:         dd      draw_prop_done                     ;0 wide
                    180:         dd      or_all_1_wide_rotated_need_last    ;nonalign, 1 wide, need last
                    181:         dd      or_all_1_wide_unrotated            ;aligned, 1 wide
                    182:         dd      or_all_1_wide_rotated_no_last      ;nonalign, 1 wide, no last
                    183:         dd      or_all_1_wide_unrotated            ;aligned, 1 wide
                    184:         dd      or_all_2_wide_rotated_need_last    ;nonalign, 2 wide, need last
                    185:         dd      or_all_2_wide_unrotated            ;aligned, 2 wide
                    186:         dd      or_all_2_wide_rotated_no_last      ;nonalign, 2 wide, no last
                    187:         dd      or_all_2_wide_unrotated            ;aligned, 2 wide
                    188:         dd      or_all_3_wide_rotated_need_last    ;nonalign, 3 wide, need last
                    189:         dd      or_all_3_wide_unrotated            ;aligned, 3 wide
                    190:         dd      or_all_3_wide_rotated_no_last      ;nonalign, 3 wide, no last
                    191:         dd      or_all_3_wide_unrotated            ;aligned, 3 wide
                    192:         dd      or_all_4_wide_rotated_need_last    ;nonalign, 4 wide, need last
                    193:         dd      or_all_4_wide_unrotated            ;aligned, 4 wide
                    194:         dd      or_all_4_wide_rotated_no_last      ;nonalign, 4 wide, no last
                    195:         dd      or_all_4_wide_unrotated            ;aligned, 4 wide
                    196: 
                    197: ; Handles arbitrarily wide glyph drawing, for case where initial byte should be
                    198: ; MOVed even if it's not aligned (intended for use in drawing the first glyph
                    199: ; in a string). Table format is:
                    200: ;  Bit   1 : 1 if don't need last source byte, 0 if do need last source byte
                    201: ;  Bit   0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
                    202:         align   4
                    203: MovInitialTableWide     label   dword
                    204:         dd      mov_first_N_wide_rotated_need_last      ;nonalign, need last
                    205:         dd      mov_first_N_wide_unrotated              ;aligned
                    206:         dd      mov_first_N_wide_rotated_no_last        ;nonalign, no last
                    207:         dd      mov_first_N_wide_unrotated              ;aligned
                    208: 
                    209: ; Handles arbitrarily wide glyph drawing, for case where initial byte should be
                    210: ; ORed if it's not aligned (intended for use in drawing all but the first glyph
                    211: ; in a string). Table format is:
                    212: ;  Bit   1 : 1 if don't need last source byte, 0 if do need last source byte
                    213: ;  Bit   0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
                    214:         align   4
                    215: OrInitialTableWide      label   dword
                    216:         dd      or_first_N_wide_rotated_need_last       ;nonalign, need last
                    217:         dd      mov_first_N_wide_unrotated              ;aligned
                    218:         dd      or_first_N_wide_rotated_no_last         ;nonalign, no last
                    219:         dd      mov_first_N_wide_unrotated              ;aligned
                    220: 
                    221: ; Handles arbitrarily wide glyph drawing, for case where all bytes should
                    222: ; be ORed (intended for use in drawing potentially overlapping glyphs).
                    223: ; Table format is:
                    224: ;  Bit   1 : 1 if don't need last source byte, 0 if do need last source byte
                    225: ;  Bit   0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
                    226:         align   4
                    227: OrAllTableWide  label   dword
                    228:         dd      or_all_N_wide_rotated_need_last ;nonalign, need last
                    229:         dd      or_all_N_wide_unrotated         ;aligned
                    230:         dd      or_all_N_wide_rotated_no_last   ;nonalign, no last
                    231:         dd      or_all_N_wide_unrotated         ;aligned
                    232: 
                    233: ; Vectors to entry points for drawing various types of text. '*' means works as
                    234: ; is but could be acclerated with a custom scanning loop.
                    235:         align   4
                    236: MasterTextTypeTable     label   dword       ;tops aligned  overlap  fixed pitch
                    237:         dd      draw_nf_ntb_o_to_temp_start ;      N          N          N *
                    238:         dd      draw_f_ntb_o_to_temp_start  ;      N          N          Y *
                    239:         dd      draw_nf_ntb_o_to_temp_start ;      N          Y          N
                    240:         dd      draw_f_ntb_o_to_temp_start  ;      N          Y          Y
                    241:         dd      draw_nf_tb_no_to_temp_start ;      Y          N          N
                    242:         dd      draw_f_tb_no_to_temp_start  ;      Y          N          Y
                    243:         dd      draw_nf_ntb_o_to_temp_start ;      Y          Y          N *
                    244:         dd      draw_f_ntb_o_to_temp_start  ;      Y          Y          Y *
                    245: 
                    246: ;-----------------------------------------------------------------------
                    247: ; Tables of pointers to optimizations for drawing up to four pixels
                    248: ; of transparent text based on the upper or lower nibble of a byte.
                    249:         align   4
                    250: xpar_high_nibble_table  label   dword
                    251:         dd      xpar_high_nibble_0
                    252:         dd      xpar_high_nibble_1
                    253:         dd      xpar_high_nibble_2
                    254:         dd      xpar_high_nibble_3
                    255:         dd      xpar_high_nibble_4
                    256:         dd      xpar_high_nibble_5
                    257:         dd      xpar_high_nibble_6
                    258:         dd      xpar_high_nibble_7
                    259:         dd      xpar_high_nibble_8
                    260:         dd      xpar_high_nibble_9
                    261:         dd      xpar_high_nibble_A
                    262:         dd      xpar_high_nibble_B
                    263:         dd      xpar_high_nibble_C
                    264:         dd      xpar_high_nibble_D
                    265:         dd      xpar_high_nibble_E
                    266:         dd      xpar_high_nibble_F
                    267: 
                    268:         align   4
                    269: xpar_low_nibble_table   label   dword
                    270:         dd      xpar_low_nibble_0
                    271:         dd      xpar_low_nibble_1
                    272:         dd      xpar_low_nibble_2
                    273:         dd      xpar_low_nibble_3
                    274:         dd      xpar_low_nibble_4
                    275:         dd      xpar_low_nibble_5
                    276:         dd      xpar_low_nibble_6
                    277:         dd      xpar_low_nibble_7
                    278:         dd      xpar_low_nibble_8
                    279:         dd      xpar_low_nibble_9
                    280:         dd      xpar_low_nibble_A
                    281:         dd      xpar_low_nibble_B
                    282:         dd      xpar_low_nibble_C
                    283:         dd      xpar_low_nibble_D
                    284:         dd      xpar_low_nibble_E
                    285:         dd      xpar_low_nibble_F
                    286: 
                    287: ; Masks for clipping for the four possible left and right edge alignments
                    288: jOpaqueLeftMasks        label   byte
                    289:         db      0ffh,00eh,00ch,008h
                    290: 
                    291: jOpaqueRightMasks       label   byte
                    292:         db      0ffh,001h,003h,007h
                    293: 
                    294: ;-----------------------------------------------------------------------;
                    295: 
                    296:         .code
                    297: 
                    298: ;-----------------------------------------------------------------------;
                    299: 
                    300: cProc vFastText,44,<\
                    301:  uses esi edi ebx,\
                    302:  ppdev:ptr,\
                    303:  pGlyphPos:ptr,\
                    304:  ulGlyphCount:dword,\
                    305:  pTempBuffer:ptr,\
                    306:  ulBufDelta:dword,\
                    307:  ulCharInc:dword,\
                    308:  prclText:ptr,\
                    309:  prclOpaque:ptr,\
                    310:  iFgColor:dword,\
                    311:  iBgColor:dword,\
                    312:  fDrawFlags:dword>
                    313: 
                    314:         local ulGlyDelta:dword  ;width per scan of source glyph, in bytes
                    315:         local ulWidthInBytes:dword ;width of glyph, in bytes
                    316:         local ulTmpWidthInBytes:dword ;working byte-width count
                    317:         local ulGlyphX:dword    ;for fixed-pitch text, maintains the current
                    318:                                 ; glyph's left-edge X coordinate
                    319:         local pGlyphLoop:dword  ;pointer to glyph-processing loop
                    320:         local ulTempLeft:dword  ;X coordinate on screen of left edge of temp
                    321:                                 ; buffer
                    322:         local pfnEntry:dword    ;pointer to unrolled loop entry point
                    323:         local ulXparBytes:dword ;general loop count storage
                    324:         local ulTmpSrcDelta:dword ;distance from end of one buffer text scan to
                    325:                                   ; start of next
                    326:         local ulTmpDstDelta:dword ;distance from end of one screen text scan to
                    327:                                   ; start of next
                    328:         local ulTopScan:dword     ;top scan of dest text rect in current bank
                    329:         local ulBottomScan:dword  ;bottom scan of dest text rect
                    330:         local ulNumScans:dword    ;# of scans to draw
                    331:         local ulScreenDelta:dword ;scan-to-scan offset in screen
                    332:         local ulScreenDeltaLinear:dword ;scan-to-scan offset in screen when in
                    333:                                         ; nice, neat linear packed-pixel mode
                    334:         local ulTextWidthInBytesMinus1:dword ;# of bytes across spanned by
                    335:                                              ; text, minus 1
                    336:         local pScreen:dword     ;pointer to first screen byte to which to draw
                    337:         local pfnEdgeVector:dword ;pointer to routine to draw any needed edges
                    338:         local pfnFirstOpaqVector:dword ;pointer to initial drawing routine
                    339:                                        ; called for opaque (either whole
                    340:                                        ; bytes, or edge(s) if no whole bytes)
                    341:         local ulWholeWidthInQuadpixelPairs:dword ;# of quadpixel pairs to copy
                    342:         local ulWholeWidthInQuadpixelPairsMinus1:dword ;# of whole bytes to
                    343:                                                        ; copy - 1
                    344:         local ulOddQuadpixel:dword      ;1 if odd quadpixel in quadpixel-pair
                    345:                                         ; copy
                    346:         local ulTextLeft:dword  ;left edge of leftmost glyph
                    347:         local ulLeftMask:dword  ;for opaque text, left edge mask for string
                    348:         local ulRightMask:dword ;for opaque text, right edge mask for string
                    349:         local ulUnrolledCount:dword    ;# of unrolled loop reps
                    350:         local ulUnrolledOddCount:dword ;# of unrolled loop odd reps
                    351:         local ulYOrigin:dword   ;Y origin of text in string (all glyphs are at
                    352:                                 ; the same Y origin)
                    353:         local pGlyphFlipTable:dword ;pointer to look-up table used to reverse
                    354:                                     ; the order of bits 0-3 and 4-7
                    355:         local ulLeftEdgeShift:dword ;amount by which to right-shift left-edge
                    356:                                     ; nibbles during opaque expansion to
                    357:                                     ; right-justify them (0 or 4)
                    358:         local ulRightEdgeShift:dword ;amount by which to right-shift right-edge
                    359:                                      ; nibbles during opaque expansion to
                    360:                                      ; right-justify them (0 or 4)
                    361:         local ulVGAWidthInBytesMinus1:dword ;# of VGA addresses from left edge
                    362:                                             ; to right edge of destination
                    363: 
                    364: ;-----------------------------------------------------------------------;
                    365: ; Set the pointer to the table used to flip glyph bits 0-3 and 4-7. This
                    366: ; table is guaranteed to be on a 256-byte boundary, so look-up can be
                    367: ; performed simply by loading the low byte of a pointer register.
                    368: ;-----------------------------------------------------------------------;
                    369: 
                    370:         mov     esi,ppdev
                    371:         mov     ebx,prclText    ;point to bounding text rect during 486
                    372:                                 ; interlock slot
                    373:         mov     eax,[esi].pdev_pjGlyphFlipTable
                    374:         mov     pGlyphFlipTable,eax
                    375: 
                    376: ;-----------------------------------------------------------------------;
                    377: ; If 8 wide, byte aligned, and opaque, handle with very fast special-case
                    378: ; code.
                    379: ;-----------------------------------------------------------------------;
                    380: 
                    381:         cmp     ulCharInc,8                     ;8 wide?
                    382:         jnz     short @F                        ;no
                    383:         cmp     fDrawFlags,5                    ;fixed pitch?
                    384:         jnz     short @F                        ;no
                    385:         cmp     prclOpaque,0                    ;opaque?
                    386:         jz      short @F                        ;no
                    387:         test    [ebx].xLeft,111b                ;byte aligned?
                    388:         jz      special_8_wide_aligned_opaque   ;yes, special-case
                    389: @@:
                    390: 
                    391: general_handler:
                    392: 
                    393:         mov     esi,ppdev
                    394:         mov     eax,[ebx].yTop
                    395:         mov     ulTopScan,eax   ;Y screen coordinate of top edge of temp buf
                    396:         mov     eax,[ebx].xLeft
                    397:         and     eax,not 7
                    398:         mov     ulTempLeft,eax  ;X screen coordinate of left edge of temp buf
                    399: 
                    400:         mov     eax,fDrawFlags
                    401: 
                    402:         mov     edx,[ebx].yBottom
                    403:         mov     ulBottomScan,edx ;bottom scan of text area
                    404: 
                    405:         jmp     MasterTextTypeTable[eax*4]
                    406: 
                    407: ;-----------------------------------------------------------------------;
                    408: ; Entry point for fixed-pitch | tops and bottoms aligned | no overlap.
                    409: ; Sets up to draw first glyph.
                    410: ;-----------------------------------------------------------------------;
                    411:         align   4
                    412: draw_f_tb_no_to_temp_start:
                    413:         mov     ebx,pGlyphPos           ;point to the first glyph to draw
                    414:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    415: 
                    416:         mov     edi,[ebx].gp_x          ;dest X coordinate
                    417:         sub     edi,ulTempLeft          ;adjust relative to the left of the
                    418:                                         ; temp buffer (we assume the text is
                    419:                                         ; right at the top of the text rect
                    420:                                         ; and hence the buffer)
                    421:         mov     ulGlyphX,edi            ;remember where this glyph started
                    422:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    423:         mov     pGlyphLoop,offset draw_f_tb_no_to_temp_loop
                    424:                                         ;draw additional characters with this
                    425:                                         ; loop
                    426:         jmp     short draw_to_temp_start_entry
                    427: 
                    428: ;-----------------------------------------------------------------------;
                    429: ; Entry point for non-fixed-pitch | tops and bottoms aligned | no overlap.
                    430: ; Sets up to draw first glyph.
                    431: ;-----------------------------------------------------------------------;
                    432:         align   4
                    433: draw_nf_tb_no_to_temp_start:
                    434:         mov     ebx,pGlyphPos           ;point to the first glyph to draw
                    435:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    436: 
                    437:         mov     edi,[ebx].gp_x          ;dest X coordinate
                    438:         sub     edi,ulTempLeft          ;adjust relative to the left of the
                    439:                                         ; temp buffer
                    440:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    441:         mov     pGlyphLoop,offset draw_nf_tb_no_to_temp_loop
                    442:                                         ;draw additional characters with this
                    443:                                         ; loop
                    444: draw_to_temp_start_entry:
                    445:         add     edi,[esi].gb_x          ;adjust to position of upper left glyph
                    446:                                         ; corner in dest
                    447:                                         ;BUGBUG add or sub?
                    448:         mov     ecx,edi
                    449:         shr     edi,3                   ;byte offset of first column of glyph
                    450:                                         ; offset of upper left of glyph in temp
                    451:                                         ; buffer
                    452:         add     edi,pTempBuffer         ;initial dest byte in temp buffer
                    453: 
                    454:         and     ecx,111b                ;bit alignment of upper left in temp
                    455: 
                    456:                                         ;calculate scan-to-scan glyph width
                    457:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    458: 
                    459:         lea     eax,[ebx+ecx+7]
                    460:         shr     eax,3                   ;# of dest bytes per scan
                    461: 
                    462:         add     ebx,7
                    463:         shr     ebx,3                   ;# of source bytes per scan
                    464: 
                    465:         mov     edx,ulBufDelta          ;width of destination buffer in bytes
                    466: 
                    467:         cmp     eax,4                   ;do we have special case code for this
                    468:                                         ; dest width?
                    469:         ja      short @F                ;no, handle as general case
                    470:                                         ;yes, handle as special case
                    471:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    472:                                         ; (last source byte not needed)
                    473:         rcl     eax,1                   ;factor last source byte status in
                    474:         cmp     cl,1                    ;carry if aligned
                    475:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    476:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    477:         add     esi,gb_aj               ;point to the first glyph byte
                    478: 
                    479:         jmp     MovInitialTableNarrow[eax*4]
                    480:                                         ;branch to draw the first glyph; never
                    481:                                         ; need to OR first glyph, because
                    482:                                         ; there's nothing there yet
                    483: 
                    484:         align   4
                    485: @@:                                     ;too wide to special case
                    486:         mov     ulWidthInBytes,eax      ;# of bytes across dest
                    487:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    488:                                         ; (last source byte not needed)
                    489:         mov     eax,0
                    490:         rcl     eax,1                   ;factor last source byte status in
                    491:         cmp     cl,1                    ;carry if aligned
                    492:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    493: 
                    494:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    495:         add     ebx,7
                    496:         shr     ebx,3                   ;glyph width in bytes
                    497:         mov     ulGlyDelta,ebx
                    498: 
                    499:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    500:         add     esi,gb_aj               ;point to the first glyph byte
                    501: 
                    502:         jmp     MovInitialTableWide[eax*4]
                    503:                                         ;branch to draw the first glyph; never
                    504:                                         ; need to OR first glyph, because
                    505:                                         ; there's nothing there yet
                    506: 
                    507: ;-----------------------------------------------------------------------;
                    508: ; Entry point for fixed-pitch | tops and bottoms not aligned | overlap.
                    509: ; Sets up to draw first glyph.
                    510: ;-----------------------------------------------------------------------;
                    511:         align   4
                    512: draw_f_ntb_o_to_temp_start:
                    513:         mov     ebx,pGlyphPos           ;point to the first glyph to draw
                    514:         mov     pGlyphLoop,offset draw_f_ntb_o_to_temp_loop
                    515:                                         ;draw additional characters with this
                    516:                                         ; loop
                    517:         mov     edi,[ebx].gp_x          ;dest X coordinate
                    518:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    519:         sub     edi,ulTempLeft          ;adjust relative to the left of the
                    520:                                         ; temp buffer
                    521:         mov     ulGlyphX,edi            ;remember where this glyph started
                    522:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    523:         add     edi,[esi].gb_x          ;adjust to position of upper left glyph
                    524:                                         ; corner in dest
                    525:         mov     ecx,edi
                    526:         shr     edi,3                   ;byte offset of first column of glyph
                    527:                                         ; offset of upper left of glyph in temp
                    528:                                         ; buffer
                    529:         jmp     short draw_to_temp_start_entry2
                    530: 
                    531: ;-----------------------------------------------------------------------;
                    532: ; Entry point for non-fixed-pitch | tops and bottoms not aligned | overlap.
                    533: ; Sets up to draw first glyph.
                    534: ;-----------------------------------------------------------------------;
                    535:         align   4
                    536: draw_nf_ntb_o_to_temp_start:
                    537:         mov     ebx,pGlyphPos           ;point to the first glyph to draw
                    538:         mov     pGlyphLoop,offset draw_nf_ntb_o_to_temp_loop
                    539:                                         ;draw additional characters with this
                    540:                                         ; loop
                    541:         mov     edi,[ebx].gp_x          ;dest X coordinate
                    542:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    543:         sub     edi,ulTempLeft          ;adjust relative to the left of the
                    544:                                         ; temp buffer
                    545:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    546:         add     edi,[esi].gb_x          ;adjust to position of upper left glyph
                    547:                                         ; corner in dest
                    548:                                         ;BUGBUG add or sub?
                    549:         mov     ecx,edi
                    550:         shr     edi,3                   ;byte offset of first column of glyph
                    551:                                         ; offset of upper left of glyph in temp
                    552:                                         ; buffer
                    553: draw_to_temp_start_entry2:
                    554:         mov     eax,[ebx].gp_y          ;dest origin Y coordinate
                    555:         sub     eax,ulTopScan           ;coord of glyph origin in temp buffer
                    556:         mov     ulYOrigin,eax           ;remember the Y origin of all glyphs
                    557:                                         ; (necessary because glyph positions
                    558:                                         ; after first aren't set for fixed-
                    559:                                         ; pitch strings)
                    560:         add     eax,[esi].gb_y          ;adjust to position of upper left glyph
                    561:                                         ; corner in dest
                    562:         mul     ulBufDelta              ;offset in buffer of top glyph scan
                    563:         add     eax,pTempBuffer         ;initial dest byte
                    564:         add     edi,eax
                    565: 
                    566:         and     ecx,111b                ;bit alignment of upper left in temp
                    567: 
                    568:                                         ;calculate scan-to-scan glyph width
                    569:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    570: 
                    571:         lea     eax,[ebx+ecx+7]
                    572:         shr     eax,3                   ;# of dest bytes per scan
                    573: 
                    574:         add     ebx,7
                    575:         shr     ebx,3                   ;# of source bytes per scan
                    576: 
                    577:         mov     edx,ulBufDelta          ;width of destination buffer in bytes
                    578: 
                    579:         cmp     eax,4                   ;do we have special case code for this
                    580:                                         ; dest width?
                    581:         ja      short @F                ;no, handle as general case
                    582:                                         ;yes, handle as special case
                    583:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    584:                                         ; (last source byte not needed)
                    585:         rcl     eax,1                   ;factor last source byte status in
                    586:         cmp     cl,1                    ;carry if aligned
                    587:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    588:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    589:         add     esi,gb_aj               ;point to the first glyph byte
                    590: 
                    591:         jmp     OrAllTableNarrow[eax*4] ;branch to draw the first glyph; OR all
                    592:                                         ; glyphs, because text may overlap
                    593: 
                    594:         align   4
                    595: @@:                                     ;too wide to special case
                    596:         mov     ulWidthInBytes,eax      ;# of bytes across dest
                    597:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    598:                                         ; (last source byte not needed)
                    599:         mov     eax,0
                    600:         rcl     eax,1                   ;factor last source byte status in
                    601:         cmp     cl,1                    ;carry if aligned
                    602:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    603: 
                    604:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    605:         add     ebx,7
                    606:         shr     ebx,3                   ;glyph width in bytes
                    607:         mov     ulGlyDelta,ebx
                    608: 
                    609:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    610:         add     esi,gb_aj               ;point to the first glyph byte
                    611: 
                    612:         jmp     OrAllTableWide[eax*4]   ;branch to draw the first glyph; OR all                                 ; glyphs, because text may overlap never
                    613:                                         ; glyphs, because text may overlap
                    614: 
                    615: ;-----------------------------------------------------------------------;
                    616: ; Loop to draw all fixed-pitch | tops and bottoms aligned | no overlap
                    617: ; glyphs after first.
                    618: ;-----------------------------------------------------------------------;
                    619:         align   4
                    620: draw_f_tb_no_to_temp_loop:
                    621:         dec     ulGlyphCount            ;any more glyphs to draw?
                    622:         jz      draw_to_screen          ;no, done
                    623:         mov     ebx,pGlyphPos
                    624:         add     ebx,size GLYPHPOS       ;point to the next glyph (the one
                    625:         mov     pGlyphPos,ebx           ; we're going to draw this time)
                    626:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    627: 
                    628:         mov     edi,ulGlyphX            ;last glyph's dest X start in temp buf
                    629:         add     edi,ulCharInc           ;this glyph's dest X start in temp buf
                    630:         mov     ulGlyphX,edi            ;remember for next glyph
                    631:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    632:         jmp     short draw_to_temp_loop_entry
                    633: 
                    634: ;-----------------------------------------------------------------------;
                    635: ; Loop to draw all non-fixed-pitch | tops and bottoms aligned | no overlap
                    636: ; glyphs after first.
                    637: ;-----------------------------------------------------------------------;
                    638:         align   4
                    639: draw_nf_tb_no_to_temp_loop:
                    640:         dec     ulGlyphCount            ;any more glyphs to draw?
                    641:         jz      draw_to_screen          ;no, done
                    642:         mov     ebx,pGlyphPos
                    643:         add     ebx,size GLYPHPOS       ;point to the next glyph (the one we're
                    644:         mov     pGlyphPos,ebx           ; going to draw this time)
                    645:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    646:         mov     edi,[ebx].gp_x          ;dest X coordinate
                    647:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    648:         sub     edi,ulTempLeft          ;adjust relative to the left edge of
                    649:                                         ; the temp buffer
                    650: 
                    651: draw_to_temp_loop_entry:
                    652:         add     edi,[esi].gb_x          ;adjust to position of upper left glyph
                    653:                                         ; corner in dest
                    654:         mov     ecx,edi                 ;pixel X coordinate in temp buffer
                    655:         shr     edi,3                   ;byte offset of first column = dest
                    656:                                         ; offset of upper left of glyph in temp
                    657:                                         ; buffer
                    658:         add     edi,pTempBuffer         ;initial dest byte
                    659: 
                    660:         and     ecx,111b                ;bit alignment of upper left in temp
                    661: 
                    662:                                         ;calculate scan-to-scan glyph width
                    663:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    664: 
                    665:         lea     eax,[ebx+ecx+7]
                    666:         shr     eax,3                   ;# of dest bytes to copy to per scan
                    667: 
                    668:         add     ebx,7
                    669:         shr     ebx,3                   ;# of source bytes to copy from per
                    670:                                         ; scan
                    671:         mov     edx,ulBufDelta          ;width of destination buffer in bytes
                    672: 
                    673:         cmp     eax,4                   ;do we have special case code for this
                    674:                                         ; dest width?
                    675:         ja      short @F                ;no, handle as general case
                    676:                                         ;yes, handle as special case
                    677:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    678:                                         ; (last source byte not needed)
                    679:         rcl     eax,1                   ;factor last source byte status in
                    680:         cmp     cl,1                    ;carry if aligned
                    681:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    682:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    683:         add     esi,gb_aj               ;point to the first glyph byte
                    684: 
                    685:         jmp     OrInitialTableNarrow[eax*4] ;branch to draw the first glyph;
                    686:                                             ; need to OR the 1st byte if
                    687:                                             ; non-aligned to avoid overwriting
                    688:                                             ; what's already there
                    689:         align   4
                    690: @@:                                     ;too wide to special case
                    691:         mov     ulWidthInBytes,eax      ;# of bytes across dest
                    692:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    693:                                         ; (last source byte not needed)
                    694:         mov     eax,0
                    695:         rcl     eax,1                   ;factor last source byte status in
                    696:         cmp     cl,1                    ;carry if aligned
                    697:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    698: 
                    699:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    700:         add     ebx,7
                    701:         shr     ebx,3                   ;glyph width in bytes
                    702:         mov     ulGlyDelta,ebx
                    703: 
                    704:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    705:         add     esi,gb_aj               ;point to the first glyph byte
                    706: 
                    707:         jmp     OrInitialTableWide[eax*4] ;branch to draw the next glyph;
                    708:                                           ; need to OR the 1st byte if
                    709:                                           ; non-aligned to avoid overwriting
                    710:                                           ; what's already there
                    711: 
                    712: ;-----------------------------------------------------------------------;
                    713: ; Loop to draw all fixed-pitch | tops and bottoms not aligned | overlap
                    714: ; glyphs after first.
                    715: ;-----------------------------------------------------------------------;
                    716:         align   4
                    717: draw_f_ntb_o_to_temp_loop:
                    718:         dec     ulGlyphCount            ;any more glyphs to draw?
                    719:         jz      draw_to_screen          ;no, done
                    720:         mov     ebx,pGlyphPos
                    721:         add     ebx,size GLYPHPOS       ;point to the next glyph (the one we're
                    722:         mov     pGlyphPos,ebx           ; going to draw this time)
                    723: 
                    724:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    725:         mov     edi,ulGlyphX            ;last glyph's dest X start in temp buf
                    726:         add     edi,ulCharInc           ;this glyph's dest X start in temp buf
                    727:         mov     ulGlyphX,edi            ;remember for next glyph
                    728:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    729: 
                    730:         jmp     short draw_to_temp_loop_entry2
                    731: 
                    732: ;-----------------------------------------------------------------------;
                    733: ; Loop to draw all non-fixed-pitch | tops and bottoms not aligned | overlap
                    734: ; glyphs after first.
                    735: ;-----------------------------------------------------------------------;
                    736:         align   4
                    737: draw_nf_ntb_o_to_temp_loop:
                    738:         dec     ulGlyphCount            ;any more glyphs to draw?
                    739:         jz      draw_to_screen          ;no, done
                    740:         mov     ebx,pGlyphPos
                    741:         add     ebx,size GLYPHPOS       ;point to the next glyph (the one we're
                    742:         mov     pGlyphPos,ebx           ; going to draw this time)
                    743: 
                    744:         mov     esi,[ebx].gp_pgdf       ;point to glyph def
                    745:         mov     edi,[ebx].gp_x          ;dest X coordinate
                    746:         mov     esi,[esi].gdf_pgb       ;point to glyph bits
                    747:         sub     edi,ulTempLeft          ;adjust relative to the left edge of
                    748:                                         ; the temp buffer
                    749: draw_to_temp_loop_entry2:
                    750:         add     edi,[esi].gb_x          ;adjust to position of upper left glyph
                    751:                                         ; corner in dest
                    752:         mov     ecx,edi                 ;pixel X coordinate in temp buffer
                    753:         shr     edi,3                   ;byte offset of first column = dest
                    754:                                         ; offset of upper left of glyph in temp
                    755:                                         ; buffer
                    756:         mov     eax,ulYOrigin           ;dest Y coordinate
                    757: 
                    758:         add     eax,[esi].gb_y          ;adjust to position of upper left glyph
                    759:                                         ; corner in dest
                    760:         mul     ulBufDelta              ;offset in buffer of top glyph scan
                    761:         add     eax,pTempBuffer         ;initial dest byte
                    762:         add     edi,eax
                    763: 
                    764:         and     ecx,111b                ;bit alignment of upper left in temp
                    765: 
                    766:                                         ;calculate scan-to-scan glyph width
                    767:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    768: 
                    769:         lea     eax,[ebx+ecx+7]
                    770:         shr     eax,3                   ;# of dest bytes to copy to per scan
                    771: 
                    772:         add     ebx,7
                    773:         shr     ebx,3                   ;# of source bytes to copy from per
                    774:                                         ; scan
                    775:         mov     edx,ulBufDelta          ;width of destination buffer in bytes
                    776: 
                    777:         cmp     eax,4                   ;do we have special case code for this
                    778:                                         ; dest width?
                    779:         ja      short @F                ;no, handle as general case
                    780:                                         ;yes, handle as special case
                    781:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    782:                                         ; (last source byte not needed)
                    783:         rcl     eax,1                   ;factor last source byte status in
                    784:         cmp     cl,1                    ;carry if aligned
                    785:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    786:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    787:         add     esi,gb_aj               ;point to the first glyph byte
                    788: 
                    789:         jmp     OrAllTableNarrow[eax*4] ;branch to draw the next glyph
                    790: 
                    791:         align   4
                    792: @@:                                     ;too wide to special case
                    793:         mov     ulWidthInBytes,eax      ;# of bytes across dest
                    794:         cmp     ebx,eax                 ;carry if more dest than source bytes
                    795:                                         ; (last source byte not needed)
                    796:         mov     eax,0
                    797:         rcl     eax,1                   ;factor last source byte status in
                    798:         cmp     cl,1                    ;carry if aligned
                    799:         rcl     eax,1                   ;factor in alignment (aligned or not)
                    800: 
                    801:         mov     ebx,[esi].gb_cx         ;glyph width in pixels
                    802:         add     ebx,7
                    803:         shr     ebx,3                   ;glyph width in bytes
                    804:         mov     ulGlyDelta,ebx
                    805: 
                    806:         mov     ebx,[esi].gb_cy         ;# of scans in glyph
                    807:         add     esi,gb_aj               ;point to the first glyph byte
                    808: 
                    809:         jmp     OrAllTableWide[eax*4]   ;branch to draw the next glyph
                    810: 
                    811: ;-----------------------------------------------------------------------;
                    812: ; Routines to draw all scans of a single glyph into the temp buffer,
                    813: ; optimized for the following cases:
                    814: ;
                    815: ;       1 to 4 byte-wide destination rectangles for each of:
                    816: ;               No rotation needed
                    817: ;               Rotation needed, same # of source as dest bytes needed
                    818: ;               Rotation needed, one less source than dest bytes needed
                    819: ;
                    820: ; Additionally, the three cases are handled for 5 and wider cases by a
                    821: ; general routine for each case.
                    822: ;
                    823: ; If rotation is needed, there are three sorts of routines:
                    824: ;
                    825: ; 1) The leftmost byte is MOVed, to initialize the byte. Succeeding bytes are
                    826: ;    MOVed. This is generally used for the leftmost glyph of a string.
                    827: ; 2) The leftmost byte is ORed into the existing byte. Succeeding bytes are
                    828: ;    MOVed. This is generally used after the leftmost glyph, because this may
                    829: ;    not be the first data written to that byte.
                    830: ; 3) All bytes are ORed. This is for drawing when characters might overlap.
                    831: ;
                    832: ; If rotation is not needed, there are two sorts of routines:
                    833: ;
                    834: ; 1) The leftmost byte is MOVed, to initialize the byte. Succeeding bytes are
                    835: ;    MOVed. This is generally used for the leftmost glyph of a string.
                    836: ; 2) All bytes are ORed. This is for drawing when characters might overlap.
                    837: ;
                    838: ; On entry:
                    839: ;       EBX = # of scans to copy
                    840: ;       CL  = right rotation
                    841: ;       EDX = ulBufDelta = width per scan of destination buffer, in bytes
                    842: ;       ESI = pointer to first glyph byte
                    843: ;       EDI = pointer to first dest buffer byte
                    844: ;       DF  = cleared
                    845: ;       ulGlyDelta = width per scan of source glyph, in bytes (wide case only)
                    846: ;       ulWidthInBytes = width of glyph, in bytes (required only for 5 and
                    847: ;               wider cases)
                    848: ;
                    849: ; On exit:
                    850: ;       Any or all of EAX, EBX, ECX, EDX, ESI, and EDI may be trashed.
                    851: 
                    852: ;-----------------------------------------------------------------------;
                    853: ; OR first byte, 1 byte wide dest, rotated.
                    854: ;-----------------------------------------------------------------------;
                    855:         align   4
                    856: or_all_1_wide_rotated_need_last:
                    857: or_all_1_wide_rotated_no_last:
                    858: or_first_1_wide_rotated_need_last:
                    859: or_first_1_wide_rotated_no_last:
                    860:         SET_UP_UNROLL_AND_BRANCH ebx,eax,or_first_1_wide_rotated_table, \
                    861:                            LOOP_UNROLL_SHIFT
                    862: 
                    863:         UNROLL_LOOP_ENTRY_TABLE or_first_1_wide_rotated_table,OF1WR, \
                    864:                                 LOOP_UNROLL_COUNT
                    865: 
                    866: MOR_FIRST_1_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
                    867: &ENTRY_LABEL&ENTRY_INDEX&:
                    868:         mov     ch,[esi]
                    869:         inc     esi
                    870:         shr     ch,cl
                    871:         or      [edi],ch
                    872:         add     edi,edx
                    873:         endm    ;-----------------------------------;
                    874: 
                    875:         align   4
                    876: or_first_1_wide_rotated_loop:
                    877:         UNROLL_LOOP     MOR_FIRST_1_WIDE_ROTATED,OF1WR,LOOP_UNROLL_COUNT
                    878:         dec     ebx
                    879:         jnz     or_first_1_wide_rotated_loop
                    880:         jmp     pGlyphLoop
                    881: 
                    882: ;-----------------------------------------------------------------------;
                    883: ; MOV first byte, 1 byte wide dest, rotated.
                    884: ;-----------------------------------------------------------------------;
                    885:         align   4
                    886: mov_first_1_wide_rotated_need_last:
                    887: mov_first_1_wide_rotated_no_last:
                    888:         SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_1_wide_rotated_table, \
                    889:                            LOOP_UNROLL_SHIFT
                    890: 
                    891:         UNROLL_LOOP_ENTRY_TABLE mov_first_1_wide_rotated_table,MF1WR, \
                    892:                                 LOOP_UNROLL_COUNT
                    893: 
                    894: MMOV_FIRST_1_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
                    895: &ENTRY_LABEL&ENTRY_INDEX&:
                    896:         mov     ch,[esi]
                    897:         inc     esi
                    898:         shr     ch,cl
                    899:         mov     [edi],ch
                    900:         add     edi,edx
                    901:         endm    ;-----------------------------------;
                    902: 
                    903:         align   4
                    904: mov_first_1_wide_rotated_loop:
                    905:         UNROLL_LOOP     MMOV_FIRST_1_WIDE_ROTATED,MF1WR,LOOP_UNROLL_COUNT
                    906:         dec     ebx
                    907:         jnz     mov_first_1_wide_rotated_loop
                    908:         jmp     pGlyphLoop
                    909: 
                    910: ;-----------------------------------------------------------------------;
                    911: ; MOV first byte, 1 byte wide dest, unrotated.
                    912: ;-----------------------------------------------------------------------;
                    913:         align   4
                    914: mov_first_1_wide_unrotated:
                    915: 
                    916:         SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_1_wide_unrotated_table, \
                    917:                            LOOP_UNROLL_SHIFT
                    918: 
                    919:         UNROLL_LOOP_ENTRY_TABLE mov_first_1_wide_unrotated_table,MF1WU, \
                    920:                                 LOOP_UNROLL_COUNT
                    921: 
                    922: MMOV_FIRST_1_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
                    923: &ENTRY_LABEL&ENTRY_INDEX&:
                    924:         mov     al,[esi]
                    925:         inc     esi
                    926:         mov     [edi],al
                    927:         add     edi,edx
                    928:         endm    ;-----------------------------------;
                    929: 
                    930:         align   4
                    931: mov_first_1_wide_unrotated_loop:
                    932:         UNROLL_LOOP     MMOV_FIRST_1_WIDE_UNROTATED,MF1WU,LOOP_UNROLL_COUNT
                    933:         dec     ebx
                    934:         jnz     mov_first_1_wide_unrotated_loop
                    935:         jmp     pGlyphLoop
                    936: 
                    937: ;-----------------------------------------------------------------------;
                    938: ; OR all bytes, 1 byte wide dest, unrotated.
                    939: ;-----------------------------------------------------------------------;
                    940:         align   4
                    941: or_all_1_wide_unrotated:
                    942:         SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_1_wide_unrotated_table, \
                    943:                            LOOP_UNROLL_SHIFT
                    944: 
                    945:         UNROLL_LOOP_ENTRY_TABLE or_all_1_wide_unrotated_table,OA1WU, \
                    946:                                 LOOP_UNROLL_COUNT
                    947: 
                    948: MOR_ALL_1_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
                    949: &ENTRY_LABEL&ENTRY_INDEX&:
                    950:         mov     al,[esi]
                    951:         inc     esi
                    952:         or      [edi],al
                    953:         add     edi,edx
                    954:         endm    ;-----------------------------------;
                    955: 
                    956:         align   4
                    957: or_all_1_wide_unrotated_loop:
                    958:         UNROLL_LOOP     MOR_ALL_1_WIDE_UNROTATED,OA1WU,LOOP_UNROLL_COUNT
                    959:         dec     ebx
                    960:         jnz     or_all_1_wide_unrotated_loop
                    961:         jmp     pGlyphLoop
                    962: 
                    963: ;-----------------------------------------------------------------------;
                    964: ; OR first byte, 2 bytes wide dest, rotated, need final source byte.
                    965: ;-----------------------------------------------------------------------;
                    966:         align   4
                    967: or_first_2_wide_rotated_need_last:
                    968:         SET_UP_UNROLL_AND_BRANCH ebx,eax,or_first_2_wide_rotated_need_table, \
                    969:                            LOOP_UNROLL_SHIFT
                    970: 
                    971:         UNROLL_LOOP_ENTRY_TABLE or_first_2_wide_rotated_need_table,OF2WRN, \
                    972:                                 LOOP_UNROLL_COUNT
                    973: 
                    974: MOR_FIRST_2_WIDE_ROTATED_NEED macro ENTRY_LABEL,ENTRY_INDEX
                    975: &ENTRY_LABEL&ENTRY_INDEX&:
                    976:         mov     ax,[esi]
                    977:         add     esi,2
                    978:         ror     ax,cl
                    979:         or      [edi],al
                    980:         mov     [edi+1],ah
                    981:         add     edi,edx
                    982:         endm    ;-----------------------------------;
                    983: 
                    984:         align   4
                    985: or_first_2_wide_rotated_need_loop:
                    986:         UNROLL_LOOP     MOR_FIRST_2_WIDE_ROTATED_NEED,OF2WRN,LOOP_UNROLL_COUNT
                    987:         dec     ebx
                    988:         jnz     or_first_2_wide_rotated_need_loop
                    989:         jmp     pGlyphLoop
                    990: 
                    991: ;-----------------------------------------------------------------------;
                    992: ; OR all bytes, 2 bytes wide dest, rotated, need final source byte.
                    993: ;-----------------------------------------------------------------------;
                    994:         align   4
                    995: or_all_2_wide_rotated_need_last:
                    996:         SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_2_wide_rotated_need_table, \
                    997:                            LOOP_UNROLL_SHIFT
                    998: 
                    999:         UNROLL_LOOP_ENTRY_TABLE or_all_2_wide_rotated_need_table,OA2WRN, \
                   1000:                                 LOOP_UNROLL_COUNT
                   1001: 
                   1002: MOR_ALL_2_WIDE_ROTATED_NEED macro ENTRY_LABEL,ENTRY_INDEX
                   1003: &ENTRY_LABEL&ENTRY_INDEX&:
                   1004:         mov     ax,[esi]
                   1005:         add     esi,2
                   1006:         ror     ax,cl
                   1007:         or      [edi],ax
                   1008:         add     edi,edx
                   1009:         endm    ;-----------------------------------;
                   1010: 
                   1011:         align   4
                   1012: or_all_2_wide_rotated_need_loop:
                   1013:         UNROLL_LOOP     MOR_ALL_2_WIDE_ROTATED_NEED,OA2WRN,LOOP_UNROLL_COUNT
                   1014:         dec     ebx
                   1015:         jnz     or_all_2_wide_rotated_need_loop
                   1016:         jmp     pGlyphLoop
                   1017: 
                   1018: ;-----------------------------------------------------------------------;
                   1019: ; MOV first byte, 2 bytes wide dest, rotated, need final source byte.
                   1020: ;-----------------------------------------------------------------------;
                   1021:         align   4
                   1022: mov_first_2_wide_rotated_need_last:
                   1023:         SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_2_wide_rotated_need_table, \
                   1024:                            LOOP_UNROLL_SHIFT
                   1025: 
                   1026:         UNROLL_LOOP_ENTRY_TABLE mov_first_2_wide_rotated_need_table,MF2WRN, \
                   1027:                                 LOOP_UNROLL_COUNT
                   1028: 
                   1029: MMOV_FIRST_2_WIDE_ROTATED_NEED macro ENTRY_LABEL,ENTRY_INDEX
                   1030: &ENTRY_LABEL&ENTRY_INDEX&:
                   1031:         mov     ax,[esi]
                   1032:         add     esi,2
                   1033:         ror     ax,cl
                   1034:         mov     [edi],ax
                   1035:         add     edi,edx
                   1036:         endm    ;-----------------------------------;
                   1037: 
                   1038:         align   4
                   1039: mov_first_2_wide_rotated_need_loop:
                   1040:         UNROLL_LOOP     MMOV_FIRST_2_WIDE_ROTATED_NEED,MF2WRN,LOOP_UNROLL_COUNT
                   1041:         dec     ebx
                   1042:         jnz     mov_first_2_wide_rotated_need_loop
                   1043:         jmp     pGlyphLoop
                   1044: 
                   1045: ;-----------------------------------------------------------------------;
                   1046: ; OR first byte, 2 bytes wide dest, rotated, don't need final source byte.
                   1047: ;-----------------------------------------------------------------------;
                   1048:         align   4
                   1049: or_first_2_wide_rotated_no_last:
                   1050:         SET_UP_UNROLL_AND_BRANCH ebx,eax,or_first_2_wide_rotated_table, \
                   1051:                            LOOP_UNROLL_SHIFT
                   1052: 
                   1053:         UNROLL_LOOP_ENTRY_TABLE or_first_2_wide_rotated_table,OF2WR, \
                   1054:                                 LOOP_UNROLL_COUNT
                   1055: 
                   1056: MOR_FIRST_2_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
                   1057: &ENTRY_LABEL&ENTRY_INDEX&:
                   1058:         sub     eax,eax
                   1059:         mov     ah,[esi]
                   1060:         inc     esi
                   1061:         shr     eax,cl
                   1062:         or      [edi],ah
                   1063:         mov     [edi+1],al
                   1064:         add     edi,edx
                   1065:         endm    ;-----------------------------------;
                   1066: 
                   1067:         align   4
                   1068: or_first_2_wide_rotated_loop:
                   1069:         UNROLL_LOOP     MOR_FIRST_2_WIDE_ROTATED,OF2WR,LOOP_UNROLL_COUNT
                   1070:         dec     ebx
                   1071:         jnz     or_first_2_wide_rotated_loop
                   1072:         jmp     pGlyphLoop
                   1073: 
                   1074: ;-----------------------------------------------------------------------;
                   1075: ; OR all bytes, 2 bytes wide dest, rotated, don't need final source byte.
                   1076: ;-----------------------------------------------------------------------;
                   1077:         align   4
                   1078: or_all_2_wide_rotated_no_last:
                   1079:         SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_2_wide_rotated_table, \
                   1080:                            LOOP_UNROLL_SHIFT
                   1081: 
                   1082:         UNROLL_LOOP_ENTRY_TABLE or_all_2_wide_rotated_table,OA2WR, \
                   1083:                                 LOOP_UNROLL_COUNT
                   1084: 
                   1085: MOR_ALL_2_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
                   1086: &ENTRY_LABEL&ENTRY_INDEX&:
                   1087:         sub     eax,eax
                   1088:         mov     al,[esi]
                   1089:         inc     esi
                   1090:         ror     ax,cl
                   1091:         or      [edi],ax
                   1092:         add     edi,edx
                   1093:         endm    ;-----------------------------------;
                   1094: 
                   1095:         align   4
                   1096: or_all_2_wide_rotated_loop:
                   1097:         UNROLL_LOOP     MOR_ALL_2_WIDE_ROTATED,OA2WR,LOOP_UNROLL_COUNT
                   1098:         dec     ebx
                   1099:         jnz     or_all_2_wide_rotated_loop
                   1100:         jmp     pGlyphLoop
                   1101: 
                   1102: ;-----------------------------------------------------------------------;
                   1103: ; MOV first byte, 2 bytes wide dest, rotated, don't need final source byte.
                   1104: ;-----------------------------------------------------------------------;
                   1105:         align   4
                   1106: mov_first_2_wide_rotated_no_last:
                   1107:         SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_2_wide_rotated_table, \
                   1108:                            LOOP_UNROLL_SHIFT
                   1109: 
                   1110:         UNROLL_LOOP_ENTRY_TABLE mov_first_2_wide_rotated_table,MF2WR, \
                   1111:                                 LOOP_UNROLL_COUNT
                   1112: 
                   1113: MMOV_FIRST_2_WIDE_ROTATED macro ENTRY_LABEL,ENTRY_INDEX
                   1114: &ENTRY_LABEL&ENTRY_INDEX&:
                   1115:         sub     eax,eax
                   1116:         mov     al,[esi]
                   1117:         inc     esi
                   1118:         ror     ax,cl
                   1119:         mov     [edi],ax
                   1120:         add     edi,edx
                   1121:         endm    ;-----------------------------------;
                   1122: 
                   1123:         align   4
                   1124: mov_first_2_wide_rotated_loop:
                   1125:         UNROLL_LOOP     MMOV_FIRST_2_WIDE_ROTATED,MF2WR,LOOP_UNROLL_COUNT
                   1126:         dec     ebx
                   1127:         jnz     mov_first_2_wide_rotated_loop
                   1128:         jmp     pGlyphLoop
                   1129: 
                   1130: ;-----------------------------------------------------------------------;
                   1131: ; MOV first byte, 2 bytes wide dest, unrotated.
                   1132: ;-----------------------------------------------------------------------;
                   1133:         align   4
                   1134: mov_first_2_wide_unrotated:
                   1135:         SET_UP_UNROLL_AND_BRANCH ebx,eax,mov_first_2_wide_unrotated_table, \
                   1136:                            LOOP_UNROLL_SHIFT
                   1137: 
                   1138:         UNROLL_LOOP_ENTRY_TABLE mov_first_2_wide_unrotated_table,MF2WU, \
                   1139:                                 LOOP_UNROLL_COUNT
                   1140: 
                   1141: MMOV_FIRST_2_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
                   1142: &ENTRY_LABEL&ENTRY_INDEX&:
                   1143:         mov     ax,[esi]
                   1144:         add     esi,2
                   1145:         mov     [edi],ax
                   1146:         add     edi,edx
                   1147:         endm    ;-----------------------------------;
                   1148: 
                   1149:         align   4
                   1150: mov_first_2_wide_unrotated_loop:
                   1151:         UNROLL_LOOP     MMOV_FIRST_2_WIDE_UNROTATED,MF2WU,LOOP_UNROLL_COUNT
                   1152:         dec     ebx
                   1153:         jnz     mov_first_2_wide_unrotated_loop
                   1154:         jmp     pGlyphLoop
                   1155: 
                   1156: ;-----------------------------------------------------------------------;
                   1157: ; OR all bytes, 2 bytes wide dest, unrotated.
                   1158: ;-----------------------------------------------------------------------;
                   1159:         align   4
                   1160: or_all_2_wide_unrotated:
                   1161:         SET_UP_UNROLL_AND_BRANCH ebx,eax,or_all_2_wide_unrotated_table, \
                   1162:                            LOOP_UNROLL_SHIFT
                   1163: 
                   1164:         UNROLL_LOOP_ENTRY_TABLE or_all_2_wide_unrotated_table,OA2WU, \
                   1165:                                 LOOP_UNROLL_COUNT
                   1166: 
                   1167: MOR_ALL_2_WIDE_UNROTATED macro ENTRY_LABEL,ENTRY_INDEX
                   1168: &ENTRY_LABEL&ENTRY_INDEX&:
                   1169:         mov     ax,[esi]
                   1170:         add     esi,2
                   1171:         or      [edi],ax
                   1172:         add     edi,edx
                   1173:         endm    ;-----------------------------------;
                   1174: 
                   1175:         align   4
                   1176: or_all_2_wide_unrotated_loop:
                   1177:         UNROLL_LOOP     MOR_ALL_2_WIDE_UNROTATED,OA2WU,LOOP_UNROLL_COUNT
                   1178:         dec     ebx
                   1179:         jnz     or_all_2_wide_unrotated_loop
                   1180:         jmp     pGlyphLoop
                   1181: 
                   1182: ;-----------------------------------------------------------------------;
                   1183: ; OR first byte, 3 bytes wide dest, rotated, need final source byte.
                   1184: ;-----------------------------------------------------------------------;
                   1185:         align   4
                   1186: or_first_3_wide_rotated_need_last:
                   1187: @@:
                   1188:         mov     al,[esi]
                   1189:         shr     al,cl
                   1190:         or      [edi],al
                   1191:         mov     ax,[esi]
                   1192:         ror     ax,cl
                   1193:         mov     [edi+1],ah
                   1194:         mov     ax,[esi+1]
                   1195:         add     esi,3
                   1196:         ror     ax,cl
                   1197:         mov     [edi+2],ah
                   1198:         add     edi,edx
                   1199:         dec     ebx
                   1200:         jnz     @B
                   1201:         jmp     pGlyphLoop
                   1202: 
                   1203: ;-----------------------------------------------------------------------;
                   1204: ; OR first byte, 3 bytes wide dest, rotated, need final source byte.
                   1205: ;-----------------------------------------------------------------------;
                   1206:         align   4
                   1207: or_all_3_wide_rotated_need_last:
                   1208: @@:
                   1209:         mov     al,[esi]
                   1210:         shr     al,cl
                   1211:         or      [edi],al
                   1212:         mov     ax,[esi]
                   1213:         ror     ax,cl
                   1214:         or      [edi+1],ah
                   1215:         mov     ax,[esi+1]
                   1216:         add     esi,3
                   1217:         ror     ax,cl
                   1218:         or      [edi+2],ah
                   1219:         add     edi,edx
                   1220:         dec     ebx
                   1221:         jnz     @B
                   1222:         jmp     pGlyphLoop
                   1223: 
                   1224: ;-----------------------------------------------------------------------;
                   1225: ; MOV first byte, 3 bytes wide dest, rotated, need final source byte.
                   1226: ;-----------------------------------------------------------------------;
                   1227:         align   4
                   1228: mov_first_3_wide_rotated_need_last:
                   1229: @@:
                   1230:         mov     al,[esi]
                   1231:         shr     al,cl
                   1232:         mov     [edi],al
                   1233:         mov     ax,[esi]
                   1234:         ror     ax,cl
                   1235:         mov     [edi+1],ah
                   1236:         mov     ax,[esi+1]
                   1237:         add     esi,3
                   1238:         ror     ax,cl
                   1239:         mov     [edi+2],ah
                   1240:         add     edi,edx
                   1241:         dec     ebx
                   1242:         jnz     @B
                   1243:         jmp     pGlyphLoop
                   1244: 
                   1245: ;-----------------------------------------------------------------------;
                   1246: ; OR first byte, 3 bytes wide dest, rotated, don't need final source byte.
                   1247: ;-----------------------------------------------------------------------;
                   1248:         align   4
                   1249: or_first_3_wide_rotated_no_last:
                   1250:         neg     cl
                   1251:         and     cl,111b         ;convert from right shift to left shift
                   1252: @@:
                   1253:         sub     eax,eax
                   1254:         mov     ax,[esi]
                   1255:         add     esi,2
                   1256:         xchg    ah,al
                   1257:         shl     eax,cl
                   1258:         mov     [edi+1],ah
                   1259:         mov     [edi+2],al
                   1260:         shr     eax,16
                   1261:         or      [edi],al
                   1262:         add     edi,edx
                   1263:         dec     ebx
                   1264:         jnz     @B
                   1265:         jmp     pGlyphLoop
                   1266: 
                   1267: ;-----------------------------------------------------------------------;
                   1268: ; OR all bytes, 3 bytes wide dest, rotated, don't need final source byte.
                   1269: ;-----------------------------------------------------------------------;
                   1270:         align   4
                   1271: or_all_3_wide_rotated_no_last:
                   1272:         neg     cl
                   1273:         and     cl,111b         ;convert from right shift to left shift
                   1274: @@:
                   1275:         sub     eax,eax
                   1276:         mov     ax,[esi]
                   1277:         add     esi,2
                   1278:         xchg    ah,al
                   1279:         shl     eax,cl
                   1280:         xchg    ah,al
                   1281:         or      [edi+1],ax
                   1282:         shr     eax,16
                   1283:         or      [edi],al
                   1284:         add     edi,edx
                   1285:         dec     ebx
                   1286:         jnz     @B
                   1287:         jmp     pGlyphLoop
                   1288: 
                   1289: ;-----------------------------------------------------------------------;
                   1290: ; MOV first byte, 3 bytes wide dest, rotated, don't need final source byte.
                   1291: ;-----------------------------------------------------------------------;
                   1292:         align   4
                   1293: mov_first_3_wide_rotated_no_last:
                   1294:         neg     cl
                   1295:         and     cl,111b         ;convert from right shift to left shift
                   1296: @@:
                   1297:         sub     eax,eax
                   1298:         mov     ax,[esi]
                   1299:         add     esi,2
                   1300:         xchg    ah,al
                   1301:         shl     eax,cl
                   1302:         mov     [edi+1],ah
                   1303:         mov     [edi+2],al
                   1304:         shr     eax,16
                   1305:         mov     [edi],al
                   1306:         add     edi,edx
                   1307:         dec     ebx
                   1308:         jnz     @B
                   1309:         jmp     pGlyphLoop
                   1310: 
                   1311: ;-----------------------------------------------------------------------;
                   1312: ; MOV first byte, 3 bytes wide dest, unrotated.
                   1313: ;-----------------------------------------------------------------------;
                   1314:         align   4
                   1315: mov_first_3_wide_unrotated:
                   1316: @@:
                   1317:         mov     ax,[esi]
                   1318:         mov     [edi],ax
                   1319:         mov     al,[esi+2]
                   1320:         add     esi,3
                   1321:         mov     [edi+2],al
                   1322:         add     edi,edx
                   1323:         dec     ebx
                   1324:         jnz     @B
                   1325:         jmp     pGlyphLoop
                   1326: 
                   1327: ;-----------------------------------------------------------------------;
                   1328: ; OR all bytes, 3 bytes wide dest, unrotated.
                   1329: ;-----------------------------------------------------------------------;
                   1330:         align   4
                   1331: or_all_3_wide_unrotated:
                   1332: @@:
                   1333:         mov     ax,[esi]
                   1334:         or      [edi],ax
                   1335:         mov     al,[esi+2]
                   1336:         add     esi,3
                   1337:         or      [edi+2],al
                   1338:         add     edi,edx
                   1339:         dec     ebx
                   1340:         jnz     @B
                   1341:         jmp     pGlyphLoop
                   1342: 
                   1343: ;-----------------------------------------------------------------------;
                   1344: ; OR first byte, 4 bytes wide dest, rotated, need final source byte.
                   1345: ;-----------------------------------------------------------------------;
                   1346:         align   4
                   1347: or_first_4_wide_rotated_need_last:
                   1348: @@:
                   1349:         mov     eax,[esi]
                   1350:         add     esi,4
                   1351:         xchg    ah,al
                   1352:         ror     eax,16
                   1353:         xchg    ah,al
                   1354:         shr     eax,cl
                   1355:         xchg    ah,al
                   1356:         mov     [edi+2],ax
                   1357:         shr     eax,16
                   1358:         mov     [edi+1],al
                   1359:         or      [edi],ah
                   1360:         add     edi,edx
                   1361:         dec     ebx
                   1362:         jnz     @B
                   1363:         jmp     pGlyphLoop
                   1364: 
                   1365: ;-----------------------------------------------------------------------;
                   1366: ; OR all bytes, 4 bytes wide dest, rotated, need final source byte.
                   1367: ;-----------------------------------------------------------------------;
                   1368:         align   4
                   1369: or_all_4_wide_rotated_need_last:
                   1370: @@:
                   1371:         mov     eax,[esi]
                   1372:         add     esi,4
                   1373:         xchg    ah,al
                   1374:         ror     eax,16
                   1375:         xchg    ah,al
                   1376:         shr     eax,cl
                   1377:         xchg    ah,al
                   1378:         ror     eax,16
                   1379:         xchg    al,ah
                   1380:         or      [edi],eax
                   1381:         add     edi,edx
                   1382:         dec     ebx
                   1383:         jnz     @B
                   1384:         jmp     pGlyphLoop
                   1385: 
                   1386: ;-----------------------------------------------------------------------;
                   1387: ; MOV first byte, 4 bytes wide dest, rotated, need final source byte.
                   1388: ;-----------------------------------------------------------------------;
                   1389:         align   4
                   1390: mov_first_4_wide_rotated_need_last:
                   1391: @@:
                   1392:         mov     eax,[esi]
                   1393:         add     esi,4
                   1394:         xchg    ah,al
                   1395:         ror     eax,16
                   1396:         xchg    ah,al
                   1397:         shr     eax,cl
                   1398:         xchg    ah,al
                   1399:         ror     eax,16
                   1400:         xchg    ah,al
                   1401:         mov     [edi],eax
                   1402:         add     edi,edx
                   1403:         dec     ebx
                   1404:         jnz     @B
                   1405:         jmp     pGlyphLoop
                   1406: 
                   1407: ;-----------------------------------------------------------------------;
                   1408: ; OR first byte, 4 bytes wide dest, rotated, don't need final source byte.
                   1409: ;-----------------------------------------------------------------------;
                   1410:         align   4
                   1411: or_first_4_wide_rotated_no_last:
                   1412: @@:
                   1413:         mov     ax,[esi]
                   1414:         xchg    ah,al
                   1415:         shl     eax,16
                   1416:         mov     ah,[esi+2]
                   1417:         add     esi,3
                   1418:         shr     eax,cl
                   1419:         xchg    ah,al
                   1420:         mov     [edi+2],ax
                   1421:         shr     eax,16
                   1422:         mov     [edi+1],al
                   1423:         or      [edi],ah
                   1424:         add     edi,edx
                   1425:         dec     ebx
                   1426:         jnz     @B
                   1427:         jmp     pGlyphLoop
                   1428: 
                   1429: ;-----------------------------------------------------------------------;
                   1430: ; OR all bytes, 4 bytes wide dest, rotated, don't need final source byte.
                   1431: ;-----------------------------------------------------------------------;
                   1432:         align   4
                   1433: or_all_4_wide_rotated_no_last:
                   1434: @@:
                   1435:         mov     ax,[esi]
                   1436:         xchg    ah,al
                   1437:         shl     eax,16
                   1438:         mov     ah,[esi+2]
                   1439:         add     esi,3
                   1440:         shr     eax,cl
                   1441:         xchg    ah,al
                   1442:         ror     eax,16
                   1443:         xchg    ah,al
                   1444:         or      [edi],eax
                   1445:         add     edi,edx
                   1446:         dec     ebx
                   1447:         jnz     @B
                   1448:         jmp     pGlyphLoop
                   1449: 
                   1450: ;-----------------------------------------------------------------------;
                   1451: ; MOV first byte, 4 bytes wide dest, rotated, don't need final source byte.
                   1452: ;-----------------------------------------------------------------------;
                   1453:         align   4
                   1454: mov_first_4_wide_rotated_no_last:
                   1455: @@:
                   1456:         mov     ax,[esi]
                   1457:         xchg    ah,al
                   1458:         shl     eax,16
                   1459:         mov     ah,[esi+2]
                   1460:         add     esi,3
                   1461:         shr     eax,cl
                   1462:         xchg    ah,al
                   1463:         ror     eax,16
                   1464:         xchg    ah,al
                   1465:         mov     [edi],eax
                   1466:         add     edi,edx
                   1467:         dec     ebx
                   1468:         jnz     @B
                   1469:         jmp     pGlyphLoop
                   1470: 
                   1471: ;-----------------------------------------------------------------------;
                   1472: ; MOV first byte, 4 bytes wide dest, unrotated.
                   1473: ;-----------------------------------------------------------------------;
                   1474:         align   4
                   1475: mov_first_4_wide_unrotated:
                   1476: @@:
                   1477:         mov     eax,[esi]
                   1478:         add     esi,4
                   1479:         mov     [edi],eax
                   1480:         add     edi,edx
                   1481:         dec     ebx
                   1482:         jnz     @B
                   1483:         jmp     pGlyphLoop
                   1484: 
                   1485: ;-----------------------------------------------------------------------;
                   1486: ; OR all bytes, 4 bytes wide dest, unrotated.
                   1487: ;-----------------------------------------------------------------------;
                   1488:         align   4
                   1489: or_all_4_wide_unrotated:
                   1490: @@:
                   1491:         mov     eax,[esi]
                   1492:         add     esi,4
                   1493:         or      [edi],eax
                   1494:         add     edi,edx
                   1495:         dec     ebx
                   1496:         jnz     @B
                   1497:         jmp     pGlyphLoop
                   1498: 
                   1499: ;-----------------------------------------------------------------------;
                   1500: ; OR first byte, n bytes wide dest, rotated, need final source byte.
                   1501: ;-----------------------------------------------------------------------;
                   1502:         align   4
                   1503: or_first_N_wide_rotated_need_last:
                   1504:         mov     eax,ulWidthInBytes
                   1505:         mov     edx,ulBufDelta
                   1506:         sub     edx,eax
                   1507:         mov     ulTmpDstDelta,edx
                   1508:         dec     eax             ;source doesn't advance after first byte, and
                   1509:                                 ; we do the first byte outside the loop
                   1510:         mov     edx,ulGlyDelta
                   1511:         sub     edx,eax
                   1512:         mov     ulTmpSrcDelta,edx
                   1513:         mov     ulTmpWidthInBytes,eax
                   1514: ofNwrnl_scan_loop:
                   1515:         mov     al,[esi]        ;do the initial, ORed byte separately
                   1516:         shr     al,cl
                   1517:         or      [edi],al
                   1518:         inc     edi
                   1519:         mov     edx,ulTmpWidthInBytes
                   1520: @@:
                   1521:         mov     ax,[esi]
                   1522:         inc     esi
                   1523:         ror     ax,cl
                   1524:         mov     [edi],ah
                   1525:         inc     edi
                   1526:         dec     edx
                   1527:         jnz     @B
                   1528:         add     esi,ulTmpSrcDelta
                   1529:         add     edi,ulTmpDstDelta
                   1530:         dec     ebx
                   1531:         jnz     ofNwrnl_scan_loop
                   1532:         jmp     pGlyphLoop
                   1533: 
                   1534: ;-----------------------------------------------------------------------;
                   1535: ; OR all bytes, n bytes wide dest, rotated, need final source byte.
                   1536: ;-----------------------------------------------------------------------;
                   1537:         align   4
                   1538: or_all_N_wide_rotated_need_last:
                   1539:         mov     eax,ulWidthInBytes
                   1540:         mov     edx,ulBufDelta
                   1541:         sub     edx,eax
                   1542:         mov     ulTmpDstDelta,edx
                   1543:         dec     eax             ;source doesn't advance after first byte, and
                   1544:                                 ; we do the first byte outside the loop
                   1545:         mov     edx,ulGlyDelta
                   1546:         sub     edx,eax
                   1547:         mov     ulTmpSrcDelta,edx
                   1548:         mov     ulTmpWidthInBytes,eax
                   1549: oaNwrnl_scan_loop:
                   1550:         mov     al,[esi]        ;do the initial, ORed byte separately
                   1551:         shr     al,cl
                   1552:         or      [edi],al
                   1553:         inc     edi
                   1554:         mov     edx,ulTmpWidthInBytes
                   1555: @@:
                   1556:         mov     ax,[esi]
                   1557:         inc     esi
                   1558:         ror     ax,cl
                   1559:         or      [edi],ah
                   1560:         inc     edi
                   1561:         dec     edx
                   1562:         jnz     @B
                   1563:         add     esi,ulTmpSrcDelta
                   1564:         add     edi,ulTmpDstDelta
                   1565:         dec     ebx
                   1566:         jnz     oaNwrnl_scan_loop
                   1567:         jmp     pGlyphLoop
                   1568: 
                   1569: ;-----------------------------------------------------------------------;
                   1570: ; MOV first byte, n bytes wide dest, rotated, need final source byte.
                   1571: ;-----------------------------------------------------------------------;
                   1572:         align   4
                   1573: mov_first_N_wide_rotated_need_last:
                   1574:         mov     eax,ulWidthInBytes
                   1575:         mov     edx,ulBufDelta
                   1576:         sub     edx,eax
                   1577:         mov     ulTmpDstDelta,edx
                   1578:         mov     eax,ulWidthInBytes
                   1579:         dec     eax             ;source doesn't advance after first byte, and
                   1580:                                 ; we do the first byte outside the loop
                   1581:         mov     edx,ulGlyDelta
                   1582:         sub     edx,eax
                   1583:         mov     ulTmpSrcDelta,edx
                   1584:         mov     ulTmpWidthInBytes,eax
                   1585: mfNwrnl_scan_loop:
                   1586:         mov     al,[esi]        ;do the initial byte separately
                   1587:         shr     al,cl
                   1588:         mov     [edi],al
                   1589:         inc     edi
                   1590:         mov     edx,ulTmpWidthInBytes
                   1591: @@:
                   1592:         mov     ax,[esi]
                   1593:         inc     esi
                   1594:         ror     ax,cl
                   1595:         mov     [edi],ah
                   1596:         inc     edi
                   1597:         dec     edx
                   1598:         jnz     @B
                   1599:         add     esi,ulTmpSrcDelta
                   1600:         add     edi,ulTmpDstDelta
                   1601:         dec     ebx
                   1602:         jnz     mfNwrnl_scan_loop
                   1603:         jmp     pGlyphLoop
                   1604: 
                   1605: ;-----------------------------------------------------------------------;
                   1606: ; OR first byte, N bytes wide dest, rotated, don't need final source byte.
                   1607: ;-----------------------------------------------------------------------;
                   1608:         align   4
                   1609: or_first_N_wide_rotated_no_last:
                   1610:         mov     eax,ulWidthInBytes
                   1611:         dec     eax             ;one less because we don't advance after the
                   1612:                                 ; last byte
                   1613:         mov     edx,ulBufDelta
                   1614:         sub     edx,eax
                   1615:         mov     ulTmpDstDelta,edx
                   1616:         dec     eax             ;source doesn't advance after first byte, and
                   1617:                                 ; we do the first & last bytes outside the
                   1618:                                 ; loop; already subtracted 1 above
                   1619:         mov     edx,ulGlyDelta
                   1620:         sub     edx,eax
                   1621:         mov     ulTmpSrcDelta,edx
                   1622:         mov     ulTmpWidthInBytes,eax
                   1623: ofNwr_scan_loop:
                   1624:         mov     al,[esi]        ;do the initial, ORed byte separately
                   1625:         shr     al,cl
                   1626:         or      [edi],al
                   1627:         inc     edi
                   1628:         mov     edx,ulTmpWidthInBytes
                   1629: @@:
                   1630:         mov     ax,[esi]
                   1631:         inc     esi
                   1632:         ror     ax,cl
                   1633:         mov     [edi],ah
                   1634:         inc     edi
                   1635:         dec     edx
                   1636:         jnz     @B
                   1637: 
                   1638:         mov     ah,[esi]        ;do the final byte separately
                   1639:         sub     al,al
                   1640:         shr     eax,cl
                   1641:         mov     [edi],al
                   1642: 
                   1643:         add     esi,ulTmpSrcDelta
                   1644:         add     edi,ulTmpDstDelta
                   1645:         dec     ebx
                   1646:         jnz     ofNwr_scan_loop
                   1647:         jmp     pGlyphLoop
                   1648: 
                   1649: ;-----------------------------------------------------------------------;
                   1650: ; OR all bytes, N bytes wide dest, rotated, don't need final source byte.
                   1651: ;-----------------------------------------------------------------------;
                   1652:         align   4
                   1653: or_all_N_wide_rotated_no_last:
                   1654:         mov     eax,ulWidthInBytes
                   1655:         dec     eax             ;one less because we don't advance after the
                   1656:                                 ; last byte
                   1657:         mov     edx,ulBufDelta
                   1658:         sub     edx,eax
                   1659:         mov     ulTmpDstDelta,edx
                   1660:         dec     eax             ;source doesn't advance after first byte, and
                   1661:                                 ; we do the first & last bytes outside the
                   1662:                                 ; loop; already subtracted 1 above
                   1663:         mov     edx,ulGlyDelta
                   1664:         sub     edx,eax
                   1665:         mov     ulTmpSrcDelta,edx
                   1666:         mov     ulTmpWidthInBytes,eax
                   1667: oaNwr_scan_loop:
                   1668:         mov     al,[esi]        ;do the initial, ORed byte separately
                   1669:         shr     al,cl
                   1670:         or      [edi],al
                   1671:         inc     edi
                   1672:         mov     edx,ulTmpWidthInBytes
                   1673: @@:
                   1674:         mov     ax,[esi]
                   1675:         inc     esi
                   1676:         ror     ax,cl
                   1677:         or      [edi],ah
                   1678:         inc     edi
                   1679:         dec     edx
                   1680:         jnz     @B
                   1681: 
                   1682:         mov     ah,[esi]        ;do the final byte separately
                   1683:         sub     al,al
                   1684:         shr     eax,cl
                   1685:         or      [edi],al
                   1686: 
                   1687:         add     esi,ulTmpSrcDelta
                   1688:         add     edi,ulTmpDstDelta
                   1689:         dec     ebx
                   1690:         jnz     oaNwr_scan_loop
                   1691:         jmp     pGlyphLoop
                   1692: 
                   1693: ;-----------------------------------------------------------------------;
                   1694: ; MOV first byte, N bytes wide dest, rotated, don't need final source byte.
                   1695: ;-----------------------------------------------------------------------;
                   1696:         align   4
                   1697: mov_first_N_wide_rotated_no_last:
                   1698:         mov     eax,ulWidthInBytes
                   1699:         dec     eax             ;one less because we don't advance after the
                   1700:                                 ; last byte
                   1701:         mov     edx,ulBufDelta
                   1702:         sub     edx,eax
                   1703:         mov     ulTmpDstDelta,edx
                   1704:         dec     eax             ;source doesn't advance after first byte, and
                   1705:                                 ; we do the first & last bytes outside the
                   1706:                                 ; loop; already subtracted 1 above
                   1707:         mov     edx,ulGlyDelta
                   1708:         sub     edx,eax
                   1709:         mov     ulTmpSrcDelta,edx
                   1710:         mov     ulTmpWidthInBytes,eax
                   1711: mfNwr_scan_loop:
                   1712:         mov     al,[esi]        ;do the initial byte separately
                   1713:         shr     al,cl
                   1714:         mov     [edi],al
                   1715:         inc     edi
                   1716:         mov     edx,ulTmpWidthInBytes
                   1717: @@:
                   1718:         mov     ax,[esi]
                   1719:         inc     esi
                   1720:         ror     ax,cl
                   1721:         mov     [edi],ah
                   1722:         inc     edi
                   1723:         dec     edx
                   1724:         jnz     @B
                   1725: 
                   1726:         mov     ah,[esi]        ;do the final byte separately
                   1727:         sub     al,al
                   1728:         shr     eax,cl
                   1729:         mov     [edi],al
                   1730: 
                   1731:         add     esi,ulTmpSrcDelta
                   1732:         add     edi,ulTmpDstDelta
                   1733:         dec     ebx
                   1734:         jnz     mfNwr_scan_loop
                   1735:         jmp     pGlyphLoop
                   1736: 
                   1737: ;-----------------------------------------------------------------------;
                   1738: ; MOV first byte, N bytes wide dest, unrotated.
                   1739: ;-----------------------------------------------------------------------;
                   1740:         align   4
                   1741: mov_first_N_wide_unrotated:
                   1742:         mov     edx,ulBufDelta
                   1743:         mov     eax,ulWidthInBytes
                   1744:         sub     edx,eax
                   1745:         shr     eax,1           ;width in words
                   1746:         jc      short odd_width ;there's at least one odd byte
                   1747:         shr     eax,1           ;width in dwords
                   1748:         jc      short two_odd_bytes ;there's an odd word
                   1749:                                 ;copy width is a dword multiple
                   1750: @@:
                   1751:         mov     ecx,eax
                   1752:         rep     movsd           ;copy as many dwords as possible
                   1753:         add     edi,edx
                   1754:         dec     ebx
                   1755:         jnz     @B
                   1756:         jmp     pGlyphLoop
                   1757: 
                   1758:         align   4
                   1759: odd_width:
                   1760:         shr     eax,1           ;width in dwords
                   1761:         jc      short three_odd_bytes ;there's an odd word and an odd byte
                   1762:                                 ;there's just an odd byte
                   1763:         inc     edx             ;because we won't advance after last byte
                   1764: @@:
                   1765:         mov     ecx,eax
                   1766:         rep     movsd           ;copy as many dwords as possible
                   1767:         mov     cl,[esi]
                   1768:         inc     esi
                   1769:         mov     [edi],cl
                   1770:         add     edi,edx
                   1771:         dec     ebx
                   1772:         jnz     @B
                   1773:         jmp     pGlyphLoop
                   1774: 
                   1775:         align   4
                   1776: two_odd_bytes:
                   1777:         add     edx,2           ;because we won't advance after last word
                   1778: @@:
                   1779:         mov     ecx,eax
                   1780:         rep     movsd           ;copy as many dwords as possible
                   1781:         mov     cx,[esi]
                   1782:         add     esi,2
                   1783:         mov     [edi],cx
                   1784:         add     edi,edx
                   1785:         dec     ebx
                   1786:         jnz     @B
                   1787:         jmp     pGlyphLoop
                   1788: 
                   1789:         align   4
                   1790: three_odd_bytes:
                   1791:         add     edx,3           ;because we won't advance after last word/byte
                   1792: @@:
                   1793:         mov     ecx,eax
                   1794:         rep     movsd           ;copy as many dwords as possible
                   1795:         mov     cx,[esi]
                   1796:         mov     [edi],cx
                   1797:         mov     cl,[esi+2]
                   1798:         add     esi,3
                   1799:         mov     [edi+2],cl
                   1800:         add     edi,edx
                   1801:         dec     ebx
                   1802:         jnz     @B
                   1803:         jmp     pGlyphLoop
                   1804: 
                   1805: ;-----------------------------------------------------------------------;
                   1806: ; OR all bytes, N bytes wide dest, unrotated.
                   1807: ;-----------------------------------------------------------------------;
                   1808:         align   4
                   1809: or_all_N_wide_unrotated:
                   1810:         mov     edx,ulBufDelta
                   1811:         mov     eax,ulWidthInBytes
                   1812:         sub     edx,eax
                   1813:         shr     eax,1           ;width in words
                   1814:         jc      short or_odd_width ;there's at least one odd byte
                   1815:         shr     eax,1           ;width in dwords
                   1816:         jc      short or_two_odd_bytes ;there's an odd word
                   1817:                                 ;copy width is a dword multiple
                   1818: or_no_odd_bytes_loop:
                   1819:         push    ebx             ;preserve scan count
                   1820:         mov     ebx,eax
                   1821: @@:
                   1822:         mov     ecx,[esi]
                   1823:         add     esi,4
                   1824:         or      [edi],ecx
                   1825:         add     edi,4           ;copy as many dwords as possible
                   1826:         dec     ebx
                   1827:         jnz     @B
                   1828:         add     edi,edx
                   1829:         pop     ebx             ;restore scan count
                   1830:         dec     ebx
                   1831:         jnz     or_no_odd_bytes_loop
                   1832:         jmp     pGlyphLoop
                   1833: 
                   1834:         align   4
                   1835: or_odd_width:
                   1836:         shr     eax,1           ;width in dwords
                   1837:         jc      short three_odd_bytes ;there's an odd word and an odd byte
                   1838:                                 ;there's just an odd byte
                   1839:         inc     edx             ;skip over last byte too
                   1840: or_one_odd_bytes_loop:
                   1841:         push    ebx             ;preserve scan count
                   1842:         mov     ebx,eax
                   1843: @@:
                   1844:         mov     ecx,[esi]
                   1845:         add     esi,4
                   1846:         or      [edi],ecx
                   1847:         add     edi,4           ;copy as many dwords as possible
                   1848:         dec     ebx
                   1849:         jnz     @B
                   1850:         mov     cl,[esi]
                   1851:         or      [edi],cl
                   1852:         inc     esi
                   1853:         add     edi,edx
                   1854:         pop     ebx             ;restore scan count
                   1855:         dec     ebx
                   1856:         jnz     or_one_odd_bytes_loop
                   1857:         jmp     pGlyphLoop
                   1858: 
                   1859:         align   4
                   1860: or_two_odd_bytes:
                   1861:         add     edx,2           ;skip over last 2 bytes too
                   1862: or_two_odd_bytes_loop:
                   1863:         push    ebx             ;preserve scan count
                   1864:         mov     ebx,eax
                   1865: @@:
                   1866:         mov     ecx,[esi]
                   1867:         add     esi,4
                   1868:         or      [edi],ecx
                   1869:         add     edi,4           ;copy as many dwords as possible
                   1870:         dec     ebx
                   1871:         jnz     @B
                   1872:         mov     cx,[esi]
                   1873:         or      [edi],cx
                   1874:         add     esi,2
                   1875:         add     edi,edx
                   1876:         pop     ebx             ;restore scan count
                   1877:         dec     ebx
                   1878:         jnz     or_two_odd_bytes_loop
                   1879:         jmp     pGlyphLoop
                   1880: 
                   1881:         align   4
                   1882: or_three_odd_bytes:
                   1883:         add     edx,3           ;skip over last 3 bytes too
                   1884: or_three_odd_bytes_loop:
                   1885:         push    ebx             ;preserve scan count
                   1886:         mov     ebx,eax
                   1887: @@:
                   1888:         mov     ecx,[esi]
                   1889:         add     esi,4
                   1890:         or      [edi],ecx
                   1891:         add     edi,4           ;copy as many dwords as possible
                   1892:         dec     ebx
                   1893:         jnz     @B
                   1894:         mov     cx,[esi]
                   1895:         or      [edi],cx
                   1896:         mov     cl,[esi+2]
                   1897:         or      [edi+2],cl
                   1898:         add     esi,3
                   1899:         add     edi,edx
                   1900:         pop     ebx             ;restore scan count
                   1901:         dec     ebx
                   1902:         jnz     or_three_odd_bytes_loop
                   1903:         jmp     pGlyphLoop
                   1904: 
                   1905: ;-----------------------------------------------------------------------;
                   1906: ; At this point, the text is drawn to the temp buffer.
                   1907: ; Now, color-expand the temp buffer to the screen.
                   1908: ;
                   1909: ; Input:
                   1910: ;       ppdev = pointer to target surface's PDEV (screen)
                   1911: ;       prclText = pointer to text bounding rectangle
                   1912: ;       prclOpaque = pointer to opaquing rectangle, if there is one
                   1913: ;       iFgColor = text color
                   1914: ;       iBgColor = opaquing rectangle color, if there is one
                   1915: ;       ulTempLeft = X coordinate on dest of left edge of temp buffer pointed
                   1916: ;               to by pTempBuffer
                   1917: ;       pTempBuffer = pointer to first byte (upper left corner) of
                   1918: ;               temp buffer into which we're drawing. This should be
                   1919: ;               word-aligned with the destination
                   1920: ;       ulBufDelta = destination scan-to-scan offset
                   1921: ;       Text drawn to temp buffer
                   1922: ;
                   1923: ;-----------------------------------------------------------------------;
                   1924:         align   4
                   1925: draw_to_screen:
                   1926: 
                   1927: ;-----------------------------------------------------------------------;
                   1928: ; Is this transparent or opaque text?
                   1929: ;-----------------------------------------------------------------------;
                   1930: 
                   1931:         cmp     prclOpaque,0
                   1932:         jnz     opaque_text
                   1933: 
                   1934: ;-----------------------------------------------------------------------;
                   1935: ; Transparent text.
                   1936: ;-----------------------------------------------------------------------;
                   1937: 
                   1938: ;-----------------------------------------------------------------------;
                   1939: ; Calculate drawing parameters.
                   1940: ;-----------------------------------------------------------------------;
                   1941: 
                   1942:         mov     esi,prclText
                   1943:         mov     ebx,ppdev
                   1944:         mov     eax,[esi].xRight
                   1945:         mov     edx,[esi].xLeft
                   1946:         and     edx,not 7
                   1947:         add     eax,7
                   1948:         sub     eax,edx
                   1949:         shr     eax,3           ;width of text in temp buffer in bytes, rounded
                   1950:         mov     ulXparBytes,eax ; up. Also number of quadpixels to draw
                   1951: 
                   1952:         mov     ecx,[ebx].pdev_lNextScan
                   1953:         mov     ulScreenDelta,ecx
                   1954:         shl     eax,3           ;each temp buffer byte maps to eight VGA
                   1955:                                 ; addresses (two quadpixels in linear mode)
                   1956:         sub     ecx,eax         ;offset to next scan in screen
                   1957:         mov     ulTmpDstDelta,ecx
                   1958: 
                   1959: ;-----------------------------------------------------------------------;
                   1960: ; Calculate the offset of the initial destination quadpixel.
                   1961: ;-----------------------------------------------------------------------;
                   1962: 
                   1963:         mov     eax,[esi].yTop
                   1964:         mul     ulScreenDelta
                   1965:         mov     edi,ulTempLeft
                   1966:         add     edi,eax         ;offset in bitmap of first quadpixel's byte
                   1967:                                 ; (remember, this is linear mode)
                   1968: ;-----------------------------------------------------------------------;
                   1969: ; Map in the bank containing the top scan of the text, if it's not
                   1970: ; mapped in already.
                   1971: ;-----------------------------------------------------------------------;
                   1972: 
                   1973:         mov     eax,[esi].yTop  ;top scan line of text
                   1974:         mov     ulTopScan,eax
                   1975:         mov     esi,pTempBuffer ;initial source address
                   1976:         cmp     eax,[ebx].pdev_rcl1WindowClip.yTop ;is text top less than
                   1977:                                                    ; current bank?
                   1978:         jl      short xpar_map_init_bank           ;yes, map in proper bank
                   1979:         cmp     eax,[ebx].pdev_rcl1WindowClip.yBottom ;text top greater than
                   1980:                                                       ; current bank?
                   1981:         jl      short xpar_init_bank_mapped     ;no, proper bank already mapped
                   1982: xpar_map_init_bank:
                   1983: 
                   1984: ; Map in the bank containing the top scan line of the fill.
                   1985: ; Preserves EBX, ESI, and EDI.
                   1986: 
                   1987:         ptrCall <dword ptr [ebx].pdev_pfnBankControl>,<ebx,eax,JustifyTop>
                   1988: 
                   1989: xpar_init_bank_mapped:
                   1990: 
                   1991:         add     edi,[ebx].pdev_pvBitmapStart    ;initial destination address
                   1992: 
                   1993: ;-----------------------------------------------------------------------;
                   1994: ; Main loop for processing fill in each bank.
                   1995: ;
                   1996: ; At start of loop, EBX->pdsurf
                   1997: ;-----------------------------------------------------------------------;
                   1998: 
                   1999: xpar_bank_loop:
                   2000:         mov     edx,ulBottomScan        ;bottom of destination rectangle
                   2001:         cmp     edx,[ebx].pdev_rcl1WindowClip.yBottom
                   2002:                                         ;which comes first, the bottom of the
                   2003:                                         ; text rect or the bottom of the
                   2004:                                         ; current bank?
                   2005:         jl      short @F                ;text bottom comes first, so draw to
                   2006:                                         ; that; this is the last bank in text
                   2007:         mov     edx,[ebx].pdev_rcl1WindowClip.yBottom
                   2008:                                         ;bank bottom comes first; draw to
                   2009:                                         ; bottom of bank
                   2010: @@:
                   2011:         sub     edx,ulTopScan           ;# of scans to draw in bank
                   2012: 
                   2013:         mov     al,byte ptr iFgColor
                   2014:         mov     ah,al
                   2015:         mov     ebx,eax
                   2016:         shl     eax,16
                   2017:         mov     ax,bx                   ;put drawing color in all bytes of EAX
                   2018: 
                   2019:         sub     ebx,ebx                 ;prepare for look-up in loop
                   2020: xpar_scan_loop:
                   2021: 
                   2022:         mov     ecx,ulXparBytes         ;number of quadpixel pairs to draw
                   2023: 
                   2024:         mov     bl,[esi]                ;get next glyph byte
                   2025:         and     bl,bl                   ;are all 8 pixels transparent?
                   2026:         jz      xpar_low_nibble_0       ;yes, just skip everything in this byte
                   2027:         shr     bl,4                    ;shift the high nibble into the low
                   2028:                                         ; nibble
                   2029:         jmp     xpar_high_nibble_table[ebx*4] ;branch to draw up to four
                   2030:                                               ; pixels, followed by a branch to
                   2031:                                               ; draw the the other nibble (up
                   2032:                                               ; to four more pixels)
                   2033:         align   4
                   2034: xpar_scan_done:
                   2035: 
                   2036:         add     edi,ulTmpDstDelta       ;point to next screen scan
                   2037: 
                   2038:         dec     edx                     ;count down scans
                   2039:         jnz     xpar_scan_loop
                   2040: 
                   2041: ;-----------------------------------------------------------------------;
                   2042: ; See if there are more banks to draw.
                   2043: ;-----------------------------------------------------------------------;
                   2044: 
                   2045:         mov     ebx,ppdev
                   2046:         mov     eax,[ebx].pdev_rcl1WindowClip.yBottom ;is the text bottom in
                   2047:         cmp     ulBottomScan,eax                       ; the current bank?
                   2048:         jnle    short do_next_xpar_bank ;no, map in the next bank and draw
                   2049: 
                   2050:         cRet    vFastText               ;yes, so we're done
                   2051: 
                   2052:         align   4
                   2053: do_next_xpar_bank:
                   2054:         mov     ulTopScan,eax
                   2055:         sub     edi,[ebx].pdev_pvBitmapStart ;convert from address to offset
                   2056:                                              ; within bitmap
                   2057:         ptrCall <dword ptr [ebx].pdev_pfnBankControl>,<ebx,eax,JustifyTop>
                   2058:                                              ;map in the bank (call preserves
                   2059:                                              ; EBX, ESI, and EDI)
                   2060:         add     edi,[ebx].pdev_pvBitmapStart ;convert from offset within bitmap
                   2061:                                              ; to address (bitmap start just
                   2062:                                              ; moved)
                   2063:         jmp     xpar_bank_loop               ;we're ready to draw to the new
                   2064:                                              ; bank
                   2065: 
                   2066: ;-----------------------------------------------------------------------
                   2067: ; Routines to draw 0-4 pixels with the color in each byte of EAX, depending
                   2068: ; on the value of the nibble describing the four pixels to draw. "high_nibble"
                   2069: ; routines draw based on the upper nibble of the byte pointed to by ESI;
                   2070: ; "low_nibble" routines draw based on the lower nibble of that byte.
                   2071: ;
                   2072: ;  EAX = color with which to draw, repeated four times
                   2073: ;  EBX = zero (0)
                   2074: ;  ECX = the number of nibble pairs (source bytes = pixels*8) to draw
                   2075: ;  EDX = not used (preserved)
                   2076: ;  ESI = pointer to first nibble pair to draw
                   2077: ;  EDI = pointer to first destination byte to which to draw
                   2078: ;
                   2079: ; Must always be entered on the high nibble and extended for an even number of
                   2080: ;  nibbles.
                   2081: 
                   2082: ;-----------------------------------------------------------------------
                   2083: ; Macro to draw the four pixels represented by the high nibble of the byte at
                   2084: ; [ESI].
                   2085: 
                   2086: DO_HIGH_NIBBLE macro
                   2087:         inc     esi             ;point to the next glyph byte
                   2088:         add     edi,8           ;point to the next destination 8-pixel set
                   2089:         dec     ecx             ;count down nibble pairs (8-pixel sets)
                   2090:         jz      xpar_scan_done  ;done with this scan
                   2091:         mov     bl,[esi]        ;not done; get next glyph byte
                   2092:         and     bl,bl           ;are all 8 pixels transparent?
                   2093:         jz      xpar_low_nibble_0 ;yes, just skip everything in this byte
                   2094:         shr     bl,4            ;shift the high nibble into the low nibble
                   2095:         jmp     xpar_high_nibble_table[ebx*4] ;branch to draw up to four pixels
                   2096:         endm
                   2097: 
                   2098: ;-----------------------------------------------------------------------
                   2099: ; Macro to draw the four pixels represented by the low nibble of the byte at
                   2100: ; [ESI].
                   2101: 
                   2102: DO_LOW_NIBBLE macro
                   2103:         mov     bl,[esi]        ;get glyph byte again, for the low nibble this
                   2104:                                 ; time
                   2105:         and     ebx,0fh         ;isolate the low nibble
                   2106:         jmp     xpar_low_nibble_table[ebx*4] ;branch to draw up to four pixels
                   2107:         endm
                   2108: 
                   2109: ;-----------------------------------------------------------------------
                   2110: 
                   2111:         align   4
                   2112: xpar_high_nibble_F:
                   2113:         mov     [edi],eax
                   2114: xpar_high_nibble_0:
                   2115:         DO_LOW_NIBBLE
                   2116: 
                   2117:         align   4
                   2118: xpar_high_nibble_E:
                   2119:         mov     [edi],ax
                   2120:         mov     [edi+2],al
                   2121:         DO_LOW_NIBBLE
                   2122: 
                   2123:         align   4
                   2124: xpar_high_nibble_D:
                   2125:         mov     [edi],ax
                   2126:         mov     [edi+3],al
                   2127:         DO_LOW_NIBBLE
                   2128: 
                   2129:         align   4
                   2130: xpar_high_nibble_C:
                   2131:         mov     [edi],ax
                   2132:         DO_LOW_NIBBLE
                   2133: 
                   2134:         align   4
                   2135: xpar_high_nibble_B:
                   2136:         mov     [edi],al
                   2137:         mov     [edi+2],ax
                   2138:         DO_LOW_NIBBLE
                   2139: 
                   2140:         align   4
                   2141: xpar_high_nibble_8:
                   2142:         mov     [edi],al
                   2143:         DO_LOW_NIBBLE
                   2144: 
                   2145:         align   4
                   2146: xpar_high_nibble_6:
                   2147:         mov     [edi+1],ax
                   2148:         DO_LOW_NIBBLE
                   2149: 
                   2150:         align   4
                   2151: xpar_high_nibble_5:
                   2152:         mov     [edi+1],al
                   2153:         mov     [edi+3],al
                   2154:         DO_LOW_NIBBLE
                   2155: 
                   2156:         align   4
                   2157: xpar_high_nibble_4:
                   2158:         mov     [edi+1],al
                   2159:         DO_LOW_NIBBLE
                   2160: 
                   2161:         align   4
                   2162: xpar_high_nibble_7:
                   2163:         mov     [edi+1],al
                   2164: xpar_high_nibble_3:
                   2165:         mov     [edi+2],ax
                   2166:         DO_LOW_NIBBLE
                   2167: 
                   2168:         align   4
                   2169: xpar_high_nibble_A:
                   2170:         mov     [edi],al
                   2171: xpar_high_nibble_2:
                   2172:         mov     [edi+2],al
                   2173:         DO_LOW_NIBBLE
                   2174: 
                   2175:         align   4
                   2176: xpar_high_nibble_9:
                   2177:         mov     [edi],al
                   2178: xpar_high_nibble_1:
                   2179:         mov     [edi+3],al
                   2180:         DO_LOW_NIBBLE
                   2181: 
                   2182: 
                   2183:         align   4
                   2184: xpar_low_nibble_0:
                   2185:         DO_HIGH_NIBBLE
                   2186: 
                   2187:         align   4
                   2188: xpar_low_nibble_F:
                   2189:         mov     [edi+4],eax
                   2190:         DO_HIGH_NIBBLE
                   2191: 
                   2192:         align   4
                   2193: xpar_low_nibble_E:
                   2194:         mov     [edi+4],ax
                   2195:         mov     [edi+6],al
                   2196:         DO_HIGH_NIBBLE
                   2197: 
                   2198:         align   4
                   2199: xpar_low_nibble_D:
                   2200:         mov     [edi+4],ax
                   2201:         mov     [edi+7],al
                   2202:         DO_HIGH_NIBBLE
                   2203: 
                   2204:         align   4
                   2205: xpar_low_nibble_C:
                   2206:         mov     [edi+4],ax
                   2207:         DO_HIGH_NIBBLE
                   2208: 
                   2209:         align   4
                   2210: xpar_low_nibble_B:
                   2211:         mov     [edi+4],al
                   2212:         mov     [edi+6],ax
                   2213:         DO_HIGH_NIBBLE
                   2214: 
                   2215:         align   4
                   2216: xpar_low_nibble_8:
                   2217:         mov     [edi+4],al
                   2218:         DO_HIGH_NIBBLE
                   2219: 
                   2220:         align   4
                   2221: xpar_low_nibble_6:
                   2222:         mov     [edi+5],ax
                   2223:         DO_HIGH_NIBBLE
                   2224: 
                   2225:         align   4
                   2226: xpar_low_nibble_5:
                   2227:         mov     [edi+5],al
                   2228:         mov     [edi+7],al
                   2229:         DO_HIGH_NIBBLE
                   2230: 
                   2231:         align   4
                   2232: xpar_low_nibble_4:
                   2233:         mov     [edi+5],al
                   2234:         DO_HIGH_NIBBLE
                   2235: 
                   2236:         align   4
                   2237: xpar_low_nibble_7:
                   2238:         mov     [edi+5],al
                   2239: xpar_low_nibble_3:
                   2240:         mov     [edi+6],ax
                   2241:         DO_HIGH_NIBBLE
                   2242: 
                   2243:         align   4
                   2244: xpar_low_nibble_A:
                   2245:         mov     [edi+4],al
                   2246: xpar_low_nibble_2:
                   2247:         mov     [edi+6],al
                   2248:         DO_HIGH_NIBBLE
                   2249: 
                   2250:         align   4
                   2251: xpar_low_nibble_9:
                   2252:         mov     [edi+4],al
                   2253: xpar_low_nibble_1:
                   2254:         mov     [edi+7],al
                   2255:         DO_HIGH_NIBBLE
                   2256: 
                   2257: 
                   2258: ;-----------------------------------------------------------------------;
                   2259: ; Opaque text.
                   2260: ;-----------------------------------------------------------------------;
                   2261: 
                   2262:         align 4
                   2263: opaque_text:
                   2264: 
                   2265: ;-----------------------------------------------------------------------;
                   2266: ; Calculate drawing parameters.
                   2267: ;-----------------------------------------------------------------------;
                   2268: 
                   2269:         mov     ebx,ppdev
                   2270:         mov     esi,prclText            ;point to bounding rectangle for text
                   2271: 
                   2272:         mov     eax,[ebx].pdev_lPlanarNextScan  ;set the screen width in
                   2273:         mov     ulScreenDelta,eax               ; quadpixels
                   2274: 
                   2275:         sub     eax,eax                 ;assume clipped edge bytes won't need
                   2276:         mov     ulLeftEdgeShift,eax     ; to be shifted into position
                   2277:         mov     ulRightEdgeShift,eax
                   2278: 
                   2279:         mov     eax,[esi].xRight
                   2280:         mov     ebx,eax
                   2281:         and     ebx,11b                         ;dest right edge % 4
                   2282:         mov     edx,[esi].xLeft
                   2283:         mov     ulTextLeft,edx                  ;remember dest left edge
                   2284:         mov     cl,jOpaqueRightMasks[ebx]       ;set right edge clip mask
                   2285:         mov     ebx,edx
                   2286:         and     ebx,11b                         ;dest left edge % 4
                   2287:         mov     ulRightMask,ecx
                   2288:         mov     cl,jOpaqueLeftMasks[ebx]        ;set left edge clip mask
                   2289:         mov     ulLeftMask,ecx
                   2290: 
                   2291:         and     edx,not 7       ;left edge, rounded down to nearest byte
                   2292:         dec     eax             ;right edge - 1
                   2293:         sub     eax,edx
                   2294:         shr     eax,3           ;width of the text in the temp buffer in bytes,
                   2295:                                 ; rounded up, minus 1. This is used to point to
                   2296:                                 ; the partial right edge, if there is one
                   2297:         mov     ulTextWidthInBytesMinus1,eax
                   2298: 
                   2299: ;-----------------------------------------------------------------------;
                   2300: ; Figure out what edges we need to handle, and calculate some info for
                   2301: ; doing whole bytes.
                   2302: ;-----------------------------------------------------------------------;
                   2303: 
                   2304:         mov     edx,[esi].xLeft
                   2305:         mov     eax,[esi].xRight
                   2306:         and     edx,not 3
                   2307:         add     eax,3
                   2308:         sub     eax,edx
                   2309:         shr     eax,2           ;width of the text in the temp buffer in
                   2310:                                 ; quadpixels, rounded up (counting all whole
                   2311:                                 ; and partial quadpixels)
                   2312:         cmp     eax,1           ;only one quadpixels total?
                   2313:         jnz     short @F        ;no
                   2314:                                 ;yes, special case a single quadpixel
                   2315:         mov     ecx,offset opaq_check_more_banks  ;assume it's a solid
                   2316:                                                   ; quadpixel
                   2317:         mov     ebx,ulLeftMask
                   2318:         and     ebx,ulRightMask
                   2319:         cmp     bl,0ffh                 ;solid quadpixel?
                   2320:         jz      short opaq_set_deltas_and_edge_vector ;yes, all set
                   2321:         mov     ulLeftMask,ebx          ;no, draw as a left edge
                   2322:         dec     eax                     ;there are no whole quadpixels
                   2323:         mov     ecx,offset opaq_draw_left_edge_only
                   2324:         test    [esi].xLeft,100b        ;is partial quadpixel in bits 0-3?
                   2325:         jnz     opaq_set_edge_vector    ;yes, no shift required, already set
                   2326:         mov     ulLeftEdgeShift,4       ;no, must shift right 4 to get into
                   2327:                                         ; bits 0-3
                   2328:         jmp     short opaq_set_edge_vector ;yes, all set
                   2329: 
                   2330:         align   4
                   2331: @@:
                   2332:         lea     edx,[eax-1]
                   2333:         mov     ulVGAWidthInBytesMinus1,edx ;offset from leftmost VGA dest byte
                   2334:                                             ; to rightmost
                   2335: 
                   2336:         test    [esi].xLeft,11b            ;is left edge a solid quadpixel?
                   2337:         jz      short opaq_left_edge_solid ;yes
                   2338:         dec     eax                        ;one less whole quadpixel
                   2339:         mov     ecx,offset opaq_draw_left_edge_only ;assume right edge is solid
                   2340:         test    [esi].xLeft,100b           ;is partial quadpixel in bits 0-3?
                   2341:         jnz     short @F                   ;yes, no shift required, already set
                   2342:         mov     ulLeftEdgeShift,4          ;no, must shift right 4 to get into
                   2343:                                            ; bits 0-3
                   2344: @@:
                   2345:         test    [esi].xRight,11b           ;is right edge a solid quadpixel?
                   2346:         jz      short opaq_set_deltas_and_edge_vector ;yes, all set
                   2347:         dec     eax                        ;one less whole quadpixel
                   2348:         mov     ecx,offset opaq_draw_both_edges ;both edges are non-solid
                   2349:         jmp     short opaq_set_right_edge_shift
                   2350: 
                   2351:         align   4
                   2352: opaq_left_edge_solid:
                   2353:         mov     ecx,offset opaq_check_more_banks  ;assume right edge is solid
                   2354:         test    [esi].xRight,11b           ;is right edge a solid quadpixel?
                   2355:         jz      short opaq_set_deltas_and_edge_vector ;yes, all set
                   2356:         dec     eax                        ;one less whole quadpixel
                   2357:         mov     ecx,offset opaq_draw_right_edge_only ;no, do non-solid right
                   2358:                                                      ; edge
                   2359: opaq_set_right_edge_shift:
                   2360:         test    [esi].xRight,100b       ;is partial quadpixel in bits 0-3?
                   2361:         jnz     short opaq_set_deltas_and_edge_vector
                   2362:                                         ;yes, no shift required, already set
                   2363:         mov     ulRightEdgeShift,4      ;no, must shift right 4 to get into
                   2364:                                         ; bits 0-3
                   2365: 
                   2366: ; At this point, EAX = # of whole quadpixels across source = # of whole bytes
                   2367: ; (addresses) across destination
                   2368: 
                   2369: opaq_set_deltas_and_edge_vector:
                   2370:         mov     edi,ulScreenDelta
                   2371:         sub     edi,eax         ;whole bytes offset to next scan in screen
                   2372:                                 ; (there are four pixels--one quadpixel--
                   2373:                                 ; at each VGA address)
                   2374:         mov     ulTmpDstDelta,edi
                   2375: 
                   2376:         mov     edx,[esi].xLeft
                   2377:         mov     edi,[esi].xRight
                   2378:         add     edx,3
                   2379:         and     edx,not 7
                   2380:         add     edi,4
                   2381:         sub     edi,edx
                   2382:         shr     edi,3           ;width of the text in the temp buffer in bytes,
                   2383:                                 ; counting bytes containing whole quadpixels
                   2384:                                 ; but not bytes containing only partial
                   2385:                                 ; quadpixels. (Remember, text bytes map to
                   2386:                                 ; quadpixel pairs; text nibbles map to
                   2387:                                 ; quadpixels)
                   2388:         sub     edi,ulBufDelta
                   2389:         neg     edi
                   2390:         mov     ulTmpSrcDelta,edi ;offset to next scan in source buffer when
                   2391:                                   ; doing whole quadpixels
                   2392: opaq_set_edge_vector:
                   2393:         mov     pfnEdgeVector,ecx       ;save address of partial-quadpixel-
                   2394:                                         ; drawing code, or end of loop if no
                   2395:                                         ; partial edge
                   2396:         mov     edx,eax                 ;# of whole quadpixels
                   2397:         mov     pfnFirstOpaqVector,offset opaq_whole_quadpixels
                   2398:                                         ;assume there are whole quadpixels
                   2399:                                         ; to copy, in which case we'll draw
                   2400:                                         ; them first, then the partial edge
                   2401:                                         ; quadpixels
                   2402:         sub     edi,edi
                   2403:         shr     edx,1                   ;# of quadpixels / 2
                   2404:         mov     ulWholeWidthInQuadpixelPairs,edx ;# of quadpixel pairs to copy
                   2405:         adc     edi,edi                 ;odd quadpixel status
                   2406:         mov     ulOddQuadpixel,edi      ;1 if there is an odd quadpixel, 0 else
                   2407:         dec     edx
                   2408:         mov     ulWholeWidthInQuadpixelPairsMinus1,edx
                   2409:                                         ;# of whole quadpixel pairs to copy,
                   2410:                                         ; minus 1 (for case with both leading
                   2411:                                         ; and trailing quadpixels)
                   2412:         cmp     eax,0                   ;are there any whole quadpixels at all?
                   2413:         jg      short @F                ;yes, we're all set
                   2414:                                         ;no, set up for edge(s) only
                   2415:         mov     pfnFirstOpaqVector,ecx  ;the edges are first and only, because
                   2416:                                         ; there are no whole quadpixels
                   2417: @@:
                   2418: 
                   2419: ;-----------------------------------------------------------------------;
                   2420: ; Determine the screen offset of the first destination byte.
                   2421: ;-----------------------------------------------------------------------;
                   2422: 
                   2423:         mov     ebx,ppdev
                   2424:         mov     eax,ulTopScan
                   2425:         mov     ecx,eax
                   2426:         mul     ulScreenDelta
                   2427:         mov     edi,[esi].xLeft
                   2428:         shr     edi,2           ;left edge screen offset in quadpixels
                   2429:         add     edi,eax
                   2430: 
                   2431: ;-----------------------------------------------------------------------;
                   2432: ; Map in the bank containing the top scan of the text, if it's not
                   2433: ; mapped in already.
                   2434: ;-----------------------------------------------------------------------;
                   2435: 
                   2436:         cmp     ecx,[ebx].pdev_rcl1PlanarClip.yTop ;is text top less than
                   2437:                                                    ; current bank?
                   2438:         jl      short opaq_map_init_bank           ;yes, map in proper bank
                   2439:         cmp     ecx,[ebx].pdev_rcl1PlanarClip.yBottom ;text top greater than
                   2440:                                                       ; current bank?
                   2441:         jl      short opaq_init_bank_mapped     ;no, proper bank already mapped
                   2442: opaq_map_init_bank:
                   2443: 
                   2444: ; Map in the bank containing the top scan line of the fill.
                   2445: ; Preserves EBX, ESI, and EDI.
                   2446: 
                   2447:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>,<ebx,ecx,JustifyTop>
                   2448: 
                   2449: opaq_init_bank_mapped:
                   2450: 
                   2451:         add     edi,[ebx].pdev_pvBitmapStart    ;initial destination address
                   2452: 
                   2453: ;-----------------------------------------------------------------------;
                   2454: ; Load the latches with the background color.
                   2455: ;-----------------------------------------------------------------------;
                   2456: 
                   2457:         sub     eax,eax
                   2458:         mov     edx,[esi].xLeft
                   2459:         and     edx,011b
                   2460:         cmp     eax,edx                 ;is the first quadpixel a full
                   2461:                                         ; quadpixel?
                   2462:         adc     eax,eax                 ;if so, EAX = 1, else EAX = 0
                   2463:         mov     edx,iBgColor
                   2464:         mov     [edi+eax],dl            ;write the bg color to the first full
                   2465:                                         ; quadpixel, in each of the four planes
                   2466:         mov     dl,[edi+eax]            ;read back the quadpixel to load the
                   2467:                                         ; latches with the bg color
                   2468: 
                   2469: ;-----------------------------------------------------------------------;
                   2470: ; Set up the VGA's hardware for read mode 0 and write mode 2, the ALUs
                   2471: ; for XOR, and the Bit Mask to 1 for bits that differ between the fg and
                   2472: ; bg, 0 for bits that are the same.
                   2473: ;-----------------------------------------------------------------------;
                   2474: 
                   2475:         mov     edx,VGA_BASE + GRAF_ADDR
                   2476:         mov     ah,byte ptr [ebx].pdev_ulrm0_wmX[2]
                   2477:                                         ;write mode 2 setting for Graphics Mode
                   2478:         mov     al,GRAF_MODE
                   2479:         out     dx,ax                   ;write mode 2 to expand glyph bits to
                   2480:                                         ; 0 or 0ffh per plane
                   2481:         mov     eax,GRAF_DATA_ROT + (DR_XOR SHL 8)
                   2482:         out     dx,ax                   ;XOR to flip latched data to make ~bg
                   2483: 
                   2484:         mov     ah,byte ptr iBgColor
                   2485:         xor     ah,byte ptr iFgColor
                   2486:         mov     al,GRAF_BIT_MASK
                   2487:         out     dx,ax                   ;pass through common fg & bg bits
                   2488:                                         ; unchanged from bg color in latches;
                   2489:                                         ; non-common bits come from XOR in the
                   2490:                                         ; ALUs, flipped from the bg to the fg
                   2491:                                         ; state if the glyph bit for the pixel
                   2492:                                         ; in that plane is 1, still in bg state
                   2493:                                         ; if the glyph bit for that plane is 0
                   2494: 
                   2495: ;-----------------------------------------------------------------------;
                   2496: ; Main loop for processing fill in each bank.
                   2497: ;
                   2498: ; At start of loop and on each loop, EBX->ppdev and EDI->first destination
                   2499: ; byte.
                   2500: ;-----------------------------------------------------------------------;
                   2501: 
                   2502: opaq_bank_loop:
                   2503:         mov     pScreen,edi             ;remember initial copy destination
                   2504: 
                   2505:         mov     edx,ulBottomScan        ;bottom of destination rectangle
                   2506:         cmp     edx,[ebx].pdev_rcl1PlanarClip.yBottom
                   2507:                                         ;which comes first, the bottom of the
                   2508:                                         ; text rect or the bottom of the
                   2509:                                         ; current bank?
                   2510:         jl      short @F                ;text bottom comes first, so draw to
                   2511:                                         ; that; this is the last bank in text
                   2512:         mov     edx,[ebx].pdev_rcl1PlanarClip.yBottom
                   2513:                                         ;bank bottom comes first; draw to
                   2514:                                         ; bottom of bank
                   2515: @@:
                   2516:         sub     edx,ulTopScan           ;# of scans to draw in bank
                   2517:         mov     ulNumScans,edx
                   2518:         jmp     pfnFirstOpaqVector      ;do first sort of drawing (whole
                   2519:                                         ; bytes, or edge(s) if no whole
                   2520:                                         ; bytes)
                   2521: 
                   2522: ;-----------------------------------------------------------------------;
                   2523: ; Draw the whole quadpixels, handling as many as possible paired into
                   2524: ; bytes so we can draw 8 pixels at a time.
                   2525: ;
                   2526: ; On entry:
                   2527: ;       EDI = first destination byte
                   2528: ;-----------------------------------------------------------------------;
                   2529:         align   4
                   2530: opaq_whole_quadpixels:
                   2531:         mov     esi,pTempBuffer         ;point to first source byte
                   2532:         mov     eax,ulTextLeft          ;left edge
                   2533:         test    eax,011b                ;is there a partial (masked) edge?
                   2534:         jz      short @f                ;no, start addresses are correct
                   2535:         inc     edi                     ;yes, skip over one dest byte for the
                   2536:                                         ; four pixels in the partial edge
                   2537:         test    eax,100b                ;do we have a partial left edge in the
                   2538:                                         ; second quadpixel?
                   2539:         jz      short @f                ;no, source start address is correct
                   2540:         inc     esi                     ;yes, skip over a source byte because
                   2541:                                         ; the partial edge is all that's in
                   2542:                                         ; this byte
                   2543: @@:
                   2544:         mov     ebx,pGlyphFlipTable     ;point to the look-up table we'll use
                   2545:                                         ; to flip the glyph bits into the form
                   2546:                                         ; required by planar mode
                   2547:         mov     edx,ulNumScans          ;# of scans to draw
                   2548: 
                   2549:                                         ;decide which copy loop to use, based
                   2550:                                         ; on the word-alignment of the dest
                   2551:                                         ; rectangle with the screen
                   2552:                                         ;the following tests rely on VGA even
                   2553:                                         ; addresses being aligned to the start
                   2554:                                         ; of corresponding source buffer bytes
                   2555:                                         ; (4-pixel sets at even VGA addresses
                   2556:                                         ; match up to the upper quadpixels of
                   2557:                                         ; source buffer bytes)
                   2558:         test    edi,1                   ;is dest word-aligned?
                   2559:         jnz     short opaq_need_leading ;no, need leading quadpixel
                   2560:                                         ;yes, no leading quadpixel
                   2561:         cmp     ulOddQuadpixel,1        ;odd width in quadpixels?
                   2562:         jnz     short opaq_scan_loop    ;no, no trailing quadpixel
                   2563:         jmp     opaq_scan_loop_t        ;yes, trailing quadpixel
                   2564: 
                   2565:         align   4
                   2566: opaq_need_leading:                      ;there's a leading quadpixel
                   2567:         cmp     ulOddQuadpixel,1        ;odd width in quadpixels?
                   2568:         jnz     opaq_scan_loop_lt       ;no, trailing quadpixel
                   2569:         jmp     opaq_scan_loop_l        ;yes, no trailing quadpixel
                   2570: 
                   2571: 
                   2572: ;-----------------------------------------------------------------------;
                   2573: ; Loops for copying whole quadpixels to the screen, as much as possible a
                   2574: ; quadpixel pair at a time.
                   2575: ; On entry:
                   2576: ;       EBX = pointer to flip table
                   2577: ;       EDX = # of scans to draw
                   2578: ;       ESI = pointer to first buffer byte from which to copy
                   2579: ;       EDI = pointer to first screen byte to which to copy
                   2580: ;       ulTmpSrcDelta = offset to next buffer scan
                   2581: ;       ulTmpDstDelta = offset to next destination (VGA) scan
                   2582: ;       ulWholeWidthInQuadpixelPairs = # of whole bytes to copy
                   2583: ;       ulWholeWidthInQuadpixelPairsMinus1 = # of whole bytes to copy, minus 1
                   2584: ; LATER could break out and optimize short runs, such as 1, 2, 3, 4 wide.
                   2585: ;-----------------------------------------------------------------------;
                   2586: 
                   2587: ;-----------------------------------------------------------------------;
                   2588: ; Loop for doing whole opaque words: no leading quadpixel, no trailing
                   2589: ; quadpixel.
                   2590: ;-----------------------------------------------------------------------;
                   2591:         align   4
                   2592: opaq_scan_loop:
                   2593: opaq_sl_row_loop:
                   2594:         mov     ecx,ulWholeWidthInQuadpixelPairs
                   2595:         inc     ecx             ;adjust for word calc
                   2596:         shr     ecx,1           ;we'll do a word per loop
                   2597:                                 ;guaranteed to have at least one word to do, or
                   2598:                                 ; we wouldn't be here
                   2599:         jnc     short opaq_sl_enter_odd
                   2600: opaq_sl_byte_loop:
                   2601:         mov     bl,[esi]        ;get the next temp buffer byte
                   2602:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2603:         inc     esi             ;point to the next temp buffer byte
                   2604:         mov     ah,al
                   2605:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2606:         mov     [edi],ax        ;draw the glyph
                   2607:         add     edi,2           ;point to the next destination address
                   2608: opaq_sl_enter_odd:
                   2609:         mov     bl,[esi]        ;get the next temp buffer byte
                   2610:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2611:         inc     esi             ;point to the next temp buffer byte
                   2612:         mov     ah,al
                   2613:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2614:         mov     [edi],ax        ;draw the glyph
                   2615:         add     edi,2           ;point to the next destination address
                   2616: 
                   2617:         dec     ecx
                   2618:         jnz     opaq_sl_byte_loop
                   2619: opaq_sl_whole_done:
                   2620:         add     esi,ulTmpSrcDelta ;point to next buffer scan
                   2621:         add     edi,ulTmpDstDelta ;point to next screen scan
                   2622:         dec     edx               ;count down scans
                   2623:         jnz     opaq_sl_row_loop
                   2624:         jmp     pfnEdgeVector     ;do the edge(s)
                   2625: 
                   2626: 
                   2627: ;-----------------------------------------------------------------------;
                   2628: ; Loop for doing whole opaque words: leading quadpixel, no trailing
                   2629: ; quadpixel.
                   2630: ;-----------------------------------------------------------------------;
                   2631:         align   4
                   2632: opaq_scan_loop_l:
                   2633: opaq_sll_row_loop:
                   2634:         mov     bl,[esi]        ;get the first temp buffer byte
                   2635:         inc     esi             ;point to the next temp buffer byte
                   2636:         mov     al,[ebx]        ;reverse the order of bits 0-3
                   2637:         mov     [edi],al        ;draw the first 4 pixels (the leading quadpixel)
                   2638:         inc     edi             ;point to the next destination address
                   2639: 
                   2640:         mov     ecx,ulWholeWidthInQuadpixelPairs
                   2641:         inc     ecx             ;adjust for word calc
                   2642:         shr     ecx,1           ;we'll do a word per loop
                   2643:         jz      short opaq_sll_whole_done
                   2644:         jnc     short opaq_sll_enter_odd
                   2645: opaq_sll_byte_loop:
                   2646:         mov     bl,[esi]        ;get the next temp buffer byte
                   2647:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2648:         inc     esi             ;point to the next temp buffer byte
                   2649:         mov     ah,al
                   2650:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2651:         mov     [edi],ax        ;draw the glyph
                   2652:         add     edi,2           ;point to the next destination address
                   2653: opaq_sll_enter_odd:
                   2654:         mov     bl,[esi]        ;get the next temp buffer byte
                   2655:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2656:         inc     esi             ;point to the next temp buffer byte
                   2657:         mov     ah,al
                   2658:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2659:         mov     [edi],ax        ;draw the glyph
                   2660:         add     edi,2           ;point to the next destination address
                   2661: 
                   2662:         dec     ecx
                   2663:         jnz     opaq_sll_byte_loop
                   2664: opaq_sll_whole_done:
                   2665:         add     esi,ulTmpSrcDelta ;point to next buffer scan
                   2666:         add     edi,ulTmpDstDelta ;point to next screen scan
                   2667:         dec     edx             ;count down scans
                   2668:         jnz     opaq_sll_row_loop
                   2669:         jmp     pfnEdgeVector   ;do the edge(s)
                   2670: 
                   2671: 
                   2672: ;-----------------------------------------------------------------------;
                   2673: ; Loop for doing whole opaque words: leading byte, trailing byte.
                   2674: ;-----------------------------------------------------------------------;
                   2675:         align   4
                   2676: opaq_scan_loop_lt:
                   2677: opaq_sllt_row_loop:
                   2678:         mov     bl,[esi]        ;get the first temp buffer byte
                   2679:         inc     esi             ;point to the next temp buffer byte
                   2680:         mov     al,[ebx]        ;reverse the order of bits 0-3
                   2681:         mov     [edi],al        ;draw the first 4 pixels (the leading quadpixel)
                   2682:         inc     edi             ;point to the next destination address
                   2683: 
                   2684:         mov     ecx,ulWholeWidthInQuadpixelPairsMinus1
                   2685:         inc     ecx             ;adjust for word calc
                   2686:         shr     ecx,1           ;we'll do a word per loop
                   2687:         jz      short opaq_sllt_whole_done
                   2688:         jnc     short opaq_sllt_enter_odd
                   2689: opaq_sllt_byte_loop:
                   2690:         mov     bl,[esi]        ;get the next temp buffer byte
                   2691:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2692:         inc     esi             ;point to the next temp buffer byte
                   2693:         mov     ah,al
                   2694:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2695:         mov     [edi],ax        ;draw the glyph
                   2696:         add     edi,2           ;point to the next destination address
                   2697: opaq_sllt_enter_odd:
                   2698:         mov     bl,[esi]        ;get the next temp buffer byte
                   2699:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2700:         inc     esi             ;point to the next temp buffer byte
                   2701:         mov     ah,al
                   2702:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2703:         mov     [edi],ax        ;draw the glyph
                   2704:         add     edi,2           ;point to the next destination address
                   2705: 
                   2706:         dec     ecx
                   2707:         jnz     opaq_sllt_byte_loop
                   2708: opaq_sllt_whole_done:
                   2709:         mov     bl,[esi]        ;get the last temp buffer byte
                   2710:         inc     esi             ;point to the next temp buffer byte
                   2711:         mov     al,[ebx]        ;reverse the order of bits 4-7
                   2712:         shr     eax,4           ;put the quadpixel in bits 0-3
                   2713:         mov     [edi],al        ;draw the last 4 pixels (the trailing quadpixel)
                   2714:         inc     edi             ;point to the next destination address
                   2715: 
                   2716:         add     esi,ulTmpSrcDelta ;point to next buffer scan
                   2717:         add     edi,ulTmpDstDelta ;point to next screen scan
                   2718:         dec     edx             ;count down scans
                   2719:         jnz     opaq_sllt_row_loop
                   2720:         jmp     pfnEdgeVector   ;do the edge(s)
                   2721: 
                   2722: ;-----------------------------------------------------------------------;
                   2723: ; Loop for doing whole opaque words: no leading byte, trailing byte.
                   2724: ;-----------------------------------------------------------------------;
                   2725:         align   4
                   2726: opaq_scan_loop_t:
                   2727: opaq_slt_row_loop:
                   2728:         mov     ecx,ulWholeWidthInQuadpixelPairs
                   2729:         inc     ecx             ;adjust for word calc
                   2730:         shr     ecx,1           ;we'll do a word per loop
                   2731:         jz      short opaq_slt_whole_done
                   2732:         jnc     short opaq_slt_enter_odd
                   2733: opaq_slt_byte_loop:
                   2734:         mov     bl,[esi]        ;get the next temp buffer byte
                   2735:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2736:         inc     esi             ;point to the next temp buffer byte
                   2737:         mov     ah,al
                   2738:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2739:         mov     [edi],ax        ;draw the glyph
                   2740:         add     edi,2           ;point to the next destination address
                   2741: opaq_slt_enter_odd:
                   2742:         mov     bl,[esi]        ;get the next temp buffer byte
                   2743:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   2744:         inc     esi             ;point to the next temp buffer byte
                   2745:         mov     ah,al
                   2746:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   2747:         mov     [edi],ax        ;draw the glyph
                   2748:         add     edi,2           ;point to the next destination address
                   2749: 
                   2750:         dec     ecx
                   2751:         jnz     opaq_slt_byte_loop
                   2752: opaq_slt_whole_done:
                   2753:         mov     bl,[esi]        ;get the last temp buffer byte
                   2754:         inc     esi             ;point to the next temp buffer byte
                   2755:         mov     al,[ebx]        ;reverse the order of bits 4-7
                   2756:         shr     eax,4           ;put the quadpixel in bits 0-3
                   2757:         mov     [edi],al        ;draw the last 4 pixels (the trailing quadpixel)
                   2758:         inc     edi             ;point to the next destination address
                   2759: 
                   2760:         add     esi,ulTmpSrcDelta ;point to next buffer scan
                   2761:         add     edi,ulTmpDstDelta ;point to next screen scan
                   2762:         dec     edx             ;count down scans
                   2763:         jnz     opaq_slt_row_loop
                   2764:         jmp     pfnEdgeVector   ;do the edge(s)
                   2765: 
                   2766: ;-----------------------------------------------------------------------;
                   2767: ; Draw a partial left edge.
                   2768: ;-----------------------------------------------------------------------;
                   2769:         align   4
                   2770: opaq_draw_left_edge_only:
                   2771: 
                   2772:         push    offset opaq_edges_done  ;return here when done with edge
                   2773: 
                   2774: opaq_draw_left_edge_only_entry:
                   2775:         mov     esi,pTempBuffer         ;source start
                   2776:         mov     edi,pScreen             ;destination (VGA) start
                   2777:         mov     ecx,ulLeftEdgeShift     ;CL=amount by which to shift byte to
                   2778:                                         ; right-justify desired quadpixel (0 or
                   2779:                                         ; 4)
                   2780:         mov     eax,ulLeftMask          ;clip mask for edge
                   2781: 
                   2782: ; Enter here to copy a partial edge, with the Map Mask set to clip, ESI
                   2783: ; pointing to the first source byte to copy, EDI pointing to the first dest
                   2784: ; byte to copy to, CL the amount by which to right-shift to get the quadpixel
                   2785: ; of interest into bits 0-3, and AL the Map Mask setting to clip the edge
                   2786: 
                   2787: opaq_draw_edge_entry:
                   2788:         push    ebp                     ;preserve stack frame pointer
                   2789: 
                   2790:         mov     edx,VGA_BASE + SEQ_DATA ;SEQ_INDEX already points to Map Mask
                   2791:         out     dx,al                   ;set Map Mask for left edge
                   2792: 
                   2793:         mov     eax,ulNumScans          ;height of text
                   2794:         and     eax,11b                 ;# of fractional quadscans to copy
                   2795:         mov     edx,ulScreenDelta       ;width of a screen scan in addresses
                   2796:         mov     ebx,dword ptr OpaqFgEdgeTable[eax*4]
                   2797:         push    ebx                     ;entry point into unrolled loop
                   2798:                                         ;***stack frame unavailable***
                   2799:         mov     eax,ulNumScans          ;height of text
                   2800:         add     eax,3
                   2801:         shr     eax,2                   ;# of whole & partial quadscans to copy
                   2802:         mov     ebx,pGlyphFlipTable     ;point to the look-up table we'll use
                   2803:                                         ; to flip the glyph bits into the form
                   2804:                                         ; required by planar mode
                   2805:         mov     ebp,ulBufDelta          ;width of a source scan in bytes
                   2806:         retn                            ;branch into the unrolled loop
                   2807: 
                   2808:         align   4
                   2809: OpaqFgEdgeTable label   dword
                   2810:         dd      opaq_edge_entry_4
                   2811:         dd      opaq_edge_entry_1
                   2812:         dd      opaq_edge_entry_2
                   2813:         dd      opaq_edge_entry_3
                   2814: 
                   2815:         align   4
                   2816: opaq_edge_loop:
                   2817: opaq_edge_entry_4:
                   2818:         mov     bl,[esi]        ;get the next text buffer byte
                   2819:         shr     bl,cl           ;move the desired quadpixel into bits 0-3
                   2820:         add     esi,ebp         ;point to the next destination byte
                   2821:         mov     bl,[ebx]        ;reverse the order of bits 0-3
                   2822:         mov     [edi],bl        ;draw up to four pixels, with the Map Mask
                   2823:                                 ; clipping, if necessary
                   2824:         add     edi,edx         ;point to the next destination byte
                   2825: opaq_edge_entry_3:
                   2826:         mov     bl,[esi]        ;get the next text buffer byte
                   2827:         shr     bl,cl           ;move the desired quadpixel into bits 0-3
                   2828:         add     esi,ebp         ;point to the next destination byte
                   2829:         mov     bl,[ebx]        ;reverse the order of bits 0-3
                   2830:         mov     [edi],bl        ;draw up to four pixels, with the Map Mask
                   2831:                                 ; clipping, if necessary
                   2832:         add     edi,edx         ;point to the next destination byte
                   2833: opaq_edge_entry_2:
                   2834:         mov     bl,[esi]        ;get the next text buffer byte
                   2835:         shr     bl,cl           ;move the desired quadpixel into bits 0-3
                   2836:         add     esi,ebp         ;point to the next destination byte
                   2837:         mov     bl,[ebx]        ;reverse the order of bits 0-3
                   2838:         mov     [edi],bl        ;draw up to four pixels, with the Map Mask
                   2839:                                 ; clipping, if necessary
                   2840:         add     edi,edx         ;point to the next destination byte
                   2841: opaq_edge_entry_1:
                   2842:         mov     bl,[esi]        ;get the next text buffer byte
                   2843:         shr     bl,cl           ;move the desired quadpixel into bits 0-3
                   2844:         add     esi,ebp         ;point to the next destination byte
                   2845:         mov     bl,[ebx]        ;reverse the order of bits 0-3
                   2846:         mov     [edi],bl        ;draw up to four pixels, with the Map Mask
                   2847:                                 ; clipping, if necessary
                   2848:         add     edi,edx         ;point to the next destination byte
                   2849: 
                   2850:         dec     eax
                   2851:         jnz     opaq_edge_loop
                   2852: 
                   2853:         pop     ebp             ;restore stack frame pointer
                   2854:                                 ;***stack frame available***
                   2855:         retn
                   2856: 
                   2857: ;-----------------------------------------------------------------------;
                   2858: ; Draw a partial right edge only. Once we've set up the pointers, this
                   2859: ; is done with exactly the same code as the left edge.
                   2860: ;-----------------------------------------------------------------------;
                   2861:         align   4
                   2862: opaq_draw_right_edge_only:
                   2863:         push    offset opaq_edges_done  ;return here when done with edge
                   2864: 
                   2865: opaq_draw_right_edge_only_entry:
                   2866:         mov     esi,ulTextWidthInBytesMinus1
                   2867:         add     esi,pTempBuffer         ;point to right edge start in buffer
                   2868:         mov     edi,ulVGAWidthInBytesMinus1
                   2869:         add     edi,pScreen             ;point to right edge start in screen
                   2870:         mov     ecx,ulRightEdgeShift    ;CL=amount by which to shift byte to
                   2871:                                         ; right-justify desired quadpixel (0 or
                   2872:                                         ; 4)
                   2873:         mov     eax,ulRightMask         ;clip mask for edge
                   2874: 
                   2875:         jmp     opaq_draw_edge_entry
                   2876: 
                   2877: ;-----------------------------------------------------------------------;
                   2878: ; Draw both left and right partial  edges. We do this by calling first
                   2879: ; the left and then the right edge drawing code.
                   2880: ;-----------------------------------------------------------------------;
                   2881:         align   4
                   2882: opaq_draw_both_edges:
                   2883:         call    opaq_draw_left_edge_only_entry
                   2884:         call    opaq_draw_right_edge_only_entry
                   2885: 
                   2886: ;-----------------------------------------------------------------------;
                   2887: ; Restore Map Mask to enable all planes, now that we're done drawing
                   2888: ; partial edges.
                   2889: ;-----------------------------------------------------------------------;
                   2890: 
                   2891: opaq_edges_done:
                   2892:         mov     al,MM_ALL
                   2893:         mov     edx,VGA_BASE + SEQ_DATA ;SEQ_INDEX already points to Map Mask
                   2894:         out     dx,al                   ;set Map Mask for left edge
                   2895: 
                   2896: ;-----------------------------------------------------------------------;
                   2897: ; See if there are more banks to draw.
                   2898: ;-----------------------------------------------------------------------;
                   2899: 
                   2900: opaq_check_more_banks:
                   2901:         mov     ebx,ppdev
                   2902:         mov     eax,[ebx].pdev_rcl1PlanarClip.yBottom ;is the text bottom in
                   2903:         cmp     ulBottomScan,eax                       ; the current bank?
                   2904:         jnle    short opaq_do_next_bank ;no, do the next bank
                   2905:                                         ;yes, so we're done
                   2906: 
                   2907: ;-----------------------------------------------------------------------;
                   2908: ; Restore the VGA's hardware to the default state.
                   2909: ; The Graphics Controller Index still points to the Bit Mask at this
                   2910: ; point.
                   2911: ;-----------------------------------------------------------------------;
                   2912: 
                   2913:         mov     edx,VGA_BASE + GRAF_DATA
                   2914:         mov     al,0ffh
                   2915:         out     dx,al                   ;enable all bits through the Bit Mask
                   2916: 
                   2917:         mov     esi,ppdev
                   2918:         dec     edx                     ;point back to the Graphics Index reg
                   2919:         mov     ah,byte ptr [esi].pdev_ulrm0_wmX[0]
                   2920:                                         ;write mode 0 setting for Graphics Mode
                   2921:         mov     al,GRAF_MODE
                   2922:         out     dx,ax                   ;write mode 0, read mode 0
                   2923: 
                   2924:         mov     eax,GRAF_DATA_ROT + (DR_SET SHL 8)
                   2925:         out     dx,ax                   ;replace mode, no rotate
                   2926: 
                   2927:         cRet    vFastText
                   2928: 
                   2929: 
                   2930:         align   4
                   2931: opaq_do_next_bank:
                   2932:         mov     esi,prclText
                   2933:         mov     ulTopScan,eax           ;this will be the top of the next bank
                   2934:         mov     ecx,eax
                   2935:         mul     ulScreenDelta
                   2936:         mov     edi,[esi].xLeft
                   2937:         shr     edi,2                   ;convert from pixels to quadpixels
                   2938:         add     edi,eax                 ;next screen byte to which to copy
                   2939: 
                   2940:         ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>,<ebx,ecx,JustifyTop>
                   2941:                                         ;map in the bank (call preserves EBX,
                   2942:                                         ; ESI, and EDI)
                   2943: 
                   2944:         add     edi,[ebx].pdev_pvBitmapStart    ;initial destination address
                   2945: 
                   2946:         mov     eax,ulBufDelta
                   2947:         mul     ulNumScans
                   2948:         add     pTempBuffer,eax         ;advance to next temp buffer scan to
                   2949:                                         ; copy
                   2950: 
                   2951:         jmp     opaq_bank_loop          ;we're ready to draw in the new bank
                   2952: 
                   2953: ;-----------------------------------------------------------------------;
                   2954: ; Special 8-wide aligned opaque drawing code. Loads the latches with the
                   2955: ; background color, sets the Bit Mask to 1 for bits that differ between
                   2956: ; the foreground and background, sets the ALUs to XOR, then uses write
                   2957: ; mode 3 to draw the glyphs. Joyously, there are no partial bytes to
                   2958: ; worry about, so we can really crank up the code.
                   2959: ;
                   2960: ; On entry:
                   2961: ;       EBX = prclText
                   2962: ;-----------------------------------------------------------------------;
                   2963:         align   4
                   2964: special_8_wide_aligned_opaque:
                   2965: 
                   2966:         mov     esi,ppdev
                   2967:         mov     edi,[ebx].yBottom
                   2968:         mov     eax,[ebx].yTop
                   2969:         sub     edi,eax                 ;height of glyphs
                   2970: 
                   2971: ;-----------------------------------------------------------------------;
                   2972: ; Map in the bank containing the top scan of the text, if it's not
                   2973: ; mapped in already.
                   2974: ;-----------------------------------------------------------------------;
                   2975: 
                   2976:         cmp     eax,[esi].pdev_rcl1PlanarClip.yTop ;is text top less than
                   2977:                                                     ; current bank?
                   2978:         jl      short s8wao_map_init_bank           ;yes, map in proper bank
                   2979:         cmp     eax,[esi].pdev_rcl1PlanarClip.yBottom ;text top greater than
                   2980:                                                        ; current bank?
                   2981:         jl      short s8wa0_init_bank_mapped   ;no, proper bank already mapped
                   2982: s8wao_map_init_bank:
                   2983: 
                   2984: ; Map in the bank containing the top scan line of the text, making sure we're
                   2985: ; in planar mode at the same time.
                   2986: ; Preserves EBX, ESI, and EDI.
                   2987: 
                   2988:         ptrCall <dword ptr [esi].pdev_pfnPlanarControl>,<esi,eax,JustifyTop>
                   2989: 
                   2990: s8wa0_init_bank_mapped:
                   2991: 
                   2992: ;-----------------------------------------------------------------------;
                   2993: ; We handle only cases where the text lies entirely in one bank.
                   2994: ; LATER handle broken rasters and/or bank-spanning cases?
                   2995: ;-----------------------------------------------------------------------;
                   2996: 
                   2997:         mov     eax,[esi].pdev_rcl1PlanarClip.yBottom
                   2998:         sub     eax,[ebx].yTop          ;maximum run in bank
                   2999:         cmp     edi,eax                 ;does all the text fit in the bank?
                   3000:         jg      general_handler         ;no, let general code handle it
                   3001: 
                   3002: ;-----------------------------------------------------------------------;
                   3003: ; Set up variables.
                   3004: ;-----------------------------------------------------------------------;
                   3005: 
                   3006:         mov     eax,edi                 ;# of scans in glyphs
                   3007:         add     eax,7
                   3008:         shr     eax,3                   ;# of unrolled loops needed to draw
                   3009:                                         ; glyph scans
                   3010:         mov     ulUnrolledCount,eax     ;# of unrolled loop reps
                   3011:         and     edi,111b                ;# of odd scans in first unrolled
                   3012:                                         ; loop
                   3013:         mov     ulUnrolledOddCount,edi  ;# of odd unrolled loop reps
                   3014: 
                   3015: ;-----------------------------------------------------------------------;
                   3016: ; Point to the first screen byte at which to draw.
                   3017: ;-----------------------------------------------------------------------;
                   3018: 
                   3019:         mov     eax,[ebx].yTop
                   3020:         mul     [esi].pdev_lPlanarNextScan
                   3021:         mov     edi,[ebx].xLeft
                   3022:         shr     edi,2
                   3023:         add     edi,eax                 ;next screen byte to which to copy
                   3024:         add     edi,[esi].pdev_pvBitmapStart   ;initial destination address
                   3025:         mov     pScreen,edi
                   3026: 
                   3027: ;-----------------------------------------------------------------------;
                   3028: ; Load the latches with the background color.
                   3029: ;-----------------------------------------------------------------------;
                   3030: 
                   3031:         mov     eax,iBgColor
                   3032:         mov     byte ptr [edi],al       ;write the bg color to the first byte
                   3033:         mov     al,[edi]                ;read back the byte to load the
                   3034:                                         ; latches with the bg color
                   3035: 
                   3036: ;-----------------------------------------------------------------------;
                   3037: ; Set up the VGA's hardware for read mode 0 and write mode 2, the ALUs
                   3038: ; for XOR, and the Bit Mask to 1 for bits that differ between the fg and
                   3039: ; bg, 0 for bits that are the same.
                   3040: ;-----------------------------------------------------------------------;
                   3041: 
                   3042:         mov     edx,VGA_BASE + GRAF_ADDR
                   3043:         mov     ah,byte ptr [esi].pdev_ulrm0_wmX[2]
                   3044:                                         ;write mode 2 setting for Graphics Mode
                   3045:         mov     al,GRAF_MODE
                   3046:         out     dx,ax                   ;write mode 2 to expand glyph bits to
                   3047:                                         ; 0 or 0ffh per plane
                   3048:         mov     eax,GRAF_DATA_ROT + (DR_XOR SHL 8)
                   3049:         out     dx,ax                   ;XOR to flip latched data to make ~bg
                   3050: 
                   3051:         mov     ah,byte ptr iBgColor
                   3052:         xor     ah,byte ptr iFgColor
                   3053:         mov     al,GRAF_BIT_MASK
                   3054:         out     dx,ax                   ;pass through common fg & bg bits
                   3055:                                         ; unchanged from bg color in latches;
                   3056:                                         ; non-common bits come from XOR in the
                   3057:                                         ; ALUs, flipped from the bg to the fg
                   3058:                                         ; state if the glyph bit for the pixel
                   3059:                                         ; in that plane is 1, still in bg state
                   3060:                                         ; if the glyph bit for that plane is 0
                   3061: 
                   3062: ;-----------------------------------------------------------------------;
                   3063: ; Set up the screen scan offset in EDX.
                   3064: ;-----------------------------------------------------------------------;
                   3065: 
                   3066:         mov     edx,[esi].pdev_lPlanarNextScan ;offset from one scan to next
                   3067: 
                   3068:         mov     ecx,ulGlyphCount
                   3069:         mov     eax,ulUnrolledOddCount  ;# of odd unrolled loop reps
                   3070:         mov     eax,dword ptr s8wao_byte_table[eax*4] ;entry point into
                   3071:         mov     pGlyphLoop,eax                        ; unrolled loop
                   3072: 
                   3073: s8wao_glyph_loop:
                   3074:         mov     ebx,pGlyphPos           ;point to the current glyph to draw
                   3075:         add     pGlyphPos,(size GLYPHPOS) ;point to the next glyph
                   3076:         mov     edi,pScreen             ;point to current glyph's screen
                   3077:                                         ; location
                   3078:         add     pScreen,2               ;point to the next glyph's screen
                   3079:                                         ; location
                   3080:         mov     esi,[ebx].gp_pgdf       ;point to current glyph def
                   3081:         mov     esi,[esi].gdf_pgb       ;point to current glyph
                   3082:         add     esi,gb_aj               ;point to the current glyph's bits
                   3083:         mov     ecx,ulUnrolledCount     ;# of unrolled loop reps
                   3084:         mov     ebx,pGlyphFlipTable     ;point to the look-up table we'll use
                   3085:                                         ; to flip the glyph bits into the form
                   3086:                                         ; required by planar mode
                   3087:         jmp     pGlyphLoop              ;branch into unrolled loop
                   3088: 
                   3089:         align   4
                   3090: s8wao_byte_table        label   dword
                   3091:         dd      s8wao_byte_8
                   3092:         dd      s8wao_byte_1
                   3093:         dd      s8wao_byte_2
                   3094:         dd      s8wao_byte_3
                   3095:         dd      s8wao_byte_4
                   3096:         dd      s8wao_byte_5
                   3097:         dd      s8wao_byte_6
                   3098:         dd      s8wao_byte_7
                   3099: 
                   3100:         align   4
                   3101: s8wao_byte_loop:
                   3102: s8wao_byte_8:
                   3103:         mov     bl,[esi]        ;get the next glyph byte
                   3104:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3105:         inc     esi             ;point to the next glyph byte
                   3106:         mov     ah,al
                   3107:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3108:         mov     [edi],ax        ;draw the glyph
                   3109:         add     edi,edx         ;point to the next destination byte
                   3110: s8wao_byte_7:
                   3111:         mov     bl,[esi]        ;get the next glyph byte
                   3112:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3113:         inc     esi             ;point to the next glyph byte
                   3114:         mov     ah,al
                   3115:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3116:         mov     [edi],ax        ;draw the glyph
                   3117:         add     edi,edx         ;point to the next destination byte
                   3118: s8wao_byte_6:
                   3119:         mov     bl,[esi]        ;get the next glyph byte
                   3120:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3121:         inc     esi             ;point to the next glyph byte
                   3122:         mov     ah,al
                   3123:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3124:         mov     [edi],ax        ;draw the glyph
                   3125:         add     edi,edx         ;point to the next destination byte
                   3126: s8wao_byte_5:
                   3127:         mov     bl,[esi]        ;get the next glyph byte
                   3128:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3129:         inc     esi             ;point to the next glyph byte
                   3130:         mov     ah,al
                   3131:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3132:         mov     [edi],ax        ;draw the glyph
                   3133:         add     edi,edx         ;point to the next destination byte
                   3134: s8wao_byte_4:
                   3135:         mov     bl,[esi]        ;get the next glyph byte
                   3136:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3137:         inc     esi             ;point to the next glyph byte
                   3138:         mov     ah,al
                   3139:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3140:         mov     [edi],ax        ;draw the glyph
                   3141:         add     edi,edx         ;point to the next destination byte
                   3142: s8wao_byte_3:
                   3143:         mov     bl,[esi]        ;get the next glyph byte
                   3144:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3145:         inc     esi             ;point to the next glyph byte
                   3146:         mov     ah,al
                   3147:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3148:         mov     [edi],ax        ;draw the glyph
                   3149:         add     edi,edx         ;point to the next destination byte
                   3150: s8wao_byte_2:
                   3151:         mov     bl,[esi]        ;get the next glyph byte
                   3152:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3153:         inc     esi             ;point to the next glyph byte
                   3154:         mov     ah,al
                   3155:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3156:         mov     [edi],ax        ;draw the glyph
                   3157:         add     edi,edx         ;point to the next destination byte
                   3158: s8wao_byte_1:
                   3159:         mov     bl,[esi]        ;get the next glyph byte
                   3160:         mov     al,[ebx]        ;reverse the order of bits 0-3 and 4-7
                   3161:         inc     esi             ;point to the next glyph byte
                   3162:         mov     ah,al
                   3163:         shr     al,4            ;first quadpixel to draw in AL, next in AH
                   3164:         mov     [edi],ax        ;draw the glyph
                   3165:         add     edi,edx         ;point to the next destination byte
                   3166: 
                   3167:         dec     ecx             ;count down glyph scans
                   3168:         jnz     s8wao_byte_loop
                   3169: 
                   3170:         dec     ulGlyphCount    ;count down glyphs
                   3171:         jnz     s8wao_glyph_loop
                   3172: 
                   3173: ;-----------------------------------------------------------------------;
                   3174: ; Restore the VGA's hardware to the default state.
                   3175: ; The Graphics Controller Index still points to the Bit Mask at this
                   3176: ; point.
                   3177: ;-----------------------------------------------------------------------;
                   3178: 
                   3179:         mov     edx,VGA_BASE + GRAF_DATA
                   3180:         mov     al,0ffh
                   3181:         out     dx,al                   ;enable all bits through the Bit Mask
                   3182: 
                   3183:         mov     esi,ppdev
                   3184:         dec     edx                     ;point back to the Graphics Index reg
                   3185:         mov     ah,byte ptr [esi].pdev_ulrm0_wmX[0]
                   3186:                                         ;write mode 0 setting for Graphics Mode
                   3187:         mov     al,GRAF_MODE
                   3188:         out     dx,ax                   ;write mode 0, read mode 0
                   3189: 
                   3190:         mov     eax,GRAF_DATA_ROT + (DR_SET SHL 8)
                   3191:         out     dx,ax                   ;replace mode, no rotate
                   3192: 
                   3193: draw_prop_done:
                   3194:         cRet    vFastText
                   3195: 
                   3196: endProc vFastText
                   3197: 
                   3198: ;-----------------------------------------------------------------------;
                   3199: ; VOID vSetWriteModes(ULONG * pulWriteModes);
                   3200: ;
                   3201: ; Sets the four bytes at *pulWriteModes to the values to be written to
                   3202: ; the Graphics Mode register to select read mode 0 and:
                   3203: ;  write mode 0, write mode 1, write mode 2, and write mode 3,
                   3204: ; respectively.
                   3205: ;
                   3206: ; Must already be in graphics mode when this is called.
                   3207: ;-----------------------------------------------------------------------;
                   3208: 
                   3209: cProc vSetWriteModes,4,<   \
                   3210:         pulWriteModes:ptr  >
                   3211: 
                   3212:         mov     edx,VGA_BASE + GRAF_ADDR
                   3213:         mov     al,GRAF_MODE
                   3214:         out     dx,al           ;point the GC Index to the Graphics Mode reg
                   3215:         inc     edx             ;point to the GC Data reg
                   3216:         in      al,dx           ;get the current setting of the Graphics Mode
                   3217:         and     eax,0fch        ;mask off the write mode fields
                   3218:         mov     ah,al
                   3219:         mov     edx,eax
                   3220:         shl     edx,16
                   3221:         or      eax,edx         ;put the Graphics Mode setting in all 4 bytes
                   3222:         mov     edx,pulWriteModes ;the mode values go here
                   3223:         or      eax,03020100h   ;insert the write mode fields
                   3224:         mov     [edx],eax       ;store the Graphics Mode settings
                   3225: 
                   3226:         cRet    vSetWriteModes
                   3227: 
                   3228: endProc vSetWriteModes
                   3229: 
                   3230: ;-----------------------------------------------------------------------;
                   3231: ; VOID vClearMemDword(PULONG * pulBuffer, ULONG ulDwordCount);
                   3232: ;
                   3233: ; Clears ulCount dwords starting at pjBuffer.
                   3234: ;-----------------------------------------------------------------------;
                   3235: 
                   3236: pulBuffer    equ [esp+8]
                   3237: ulDwordCount equ [esp+12]
                   3238: 
                   3239: cProc vClearMemDword,8,<>
                   3240: 
                   3241:         push    edi
                   3242:         mov     edi,pulBuffer
                   3243:         mov     ecx,ulDwordCount
                   3244:         sub     eax,eax
                   3245:         rep     stosd
                   3246:         pop     edi
                   3247: 
                   3248:         cRet  vClearMemDword
                   3249: 
                   3250: endProc vClearMemDword
                   3251: 
                   3252: public general_handler
                   3253: public draw_f_tb_no_to_temp_start
                   3254: public draw_nf_tb_no_to_temp_start
                   3255: public draw_to_temp_start_entry
                   3256: public draw_f_ntb_o_to_temp_start
                   3257: public draw_nf_ntb_o_to_temp_start
                   3258: public draw_to_temp_start_entry2
                   3259: public draw_f_tb_no_to_temp_loop
                   3260: public draw_nf_tb_no_to_temp_loop
                   3261: public draw_to_temp_loop_entry
                   3262: public draw_f_ntb_o_to_temp_loop
                   3263: public draw_nf_ntb_o_to_temp_loop
                   3264: public draw_to_temp_loop_entry2
                   3265: public or_all_1_wide_rotated_need_last
                   3266: public or_all_1_wide_rotated_no_last
                   3267: public or_first_1_wide_rotated_need_last
                   3268: public or_first_1_wide_rotated_no_last
                   3269: public or_first_1_wide_rotated_loop
                   3270: public mov_first_1_wide_rotated_need_last
                   3271: public mov_first_1_wide_rotated_no_last
                   3272: public mov_first_1_wide_rotated_loop
                   3273: public mov_first_1_wide_unrotated
                   3274: public mov_first_1_wide_unrotated_loop
                   3275: public or_all_1_wide_unrotated
                   3276: public or_all_1_wide_unrotated_loop
                   3277: public or_first_2_wide_rotated_need_last
                   3278: public or_first_2_wide_rotated_need_loop
                   3279: public or_all_2_wide_rotated_need_last
                   3280: public or_all_2_wide_rotated_need_loop
                   3281: public mov_first_2_wide_rotated_need_last
                   3282: public mov_first_2_wide_rotated_need_loop
                   3283: public or_first_2_wide_rotated_no_last
                   3284: public or_first_2_wide_rotated_loop
                   3285: public or_all_2_wide_rotated_no_last
                   3286: public or_all_2_wide_rotated_loop
                   3287: public mov_first_2_wide_rotated_no_last
                   3288: public mov_first_2_wide_rotated_loop
                   3289: public mov_first_2_wide_unrotated
                   3290: public mov_first_2_wide_unrotated_loop
                   3291: public or_all_2_wide_unrotated
                   3292: public or_all_2_wide_unrotated_loop
                   3293: public or_first_3_wide_rotated_need_last
                   3294: public or_all_3_wide_rotated_need_last
                   3295: public mov_first_3_wide_rotated_need_last
                   3296: public or_first_3_wide_rotated_no_last
                   3297: public or_all_3_wide_rotated_no_last
                   3298: public mov_first_3_wide_rotated_no_last
                   3299: public mov_first_3_wide_unrotated
                   3300: public or_all_3_wide_unrotated
                   3301: public or_first_4_wide_rotated_need_last
                   3302: public or_all_4_wide_rotated_need_last
                   3303: public mov_first_4_wide_rotated_need_last
                   3304: public or_first_4_wide_rotated_no_last
                   3305: public or_all_4_wide_rotated_no_last
                   3306: public mov_first_4_wide_rotated_no_last
                   3307: public mov_first_4_wide_unrotated
                   3308: public or_all_4_wide_unrotated
                   3309: public or_first_N_wide_rotated_need_last
                   3310: public or_all_N_wide_rotated_need_last
                   3311: public mov_first_N_wide_rotated_need_last
                   3312: public or_first_N_wide_rotated_no_last
                   3313: public or_all_N_wide_rotated_no_last
                   3314: public mov_first_N_wide_rotated_no_last
                   3315: public mov_first_N_wide_unrotated
                   3316: public odd_width
                   3317: public two_odd_bytes
                   3318: public three_odd_bytes
                   3319: public or_all_N_wide_unrotated
                   3320: public or_no_odd_bytes_loop
                   3321: public or_odd_width
                   3322: public or_one_odd_bytes_loop
                   3323: public or_two_odd_bytes
                   3324: public or_two_odd_bytes_loop
                   3325: public or_three_odd_bytes
                   3326: public or_three_odd_bytes_loop
                   3327: public draw_to_screen
                   3328: public opaque_text
                   3329: public opaq_left_edge_solid
                   3330: public opaq_set_edge_vector
                   3331: public opaq_map_init_bank
                   3332: public opaq_init_bank_mapped
                   3333: public opaq_bank_loop
                   3334: public opaq_whole_quadpixels
                   3335: public opaq_scan_loop
                   3336: public opaq_scan_loop_l
                   3337: public opaq_scan_loop_lt
                   3338: public opaq_scan_loop_t
                   3339: public opaq_draw_left_edge_only
                   3340: public opaq_draw_left_edge_only_entry
                   3341: public opaq_edge_loop
                   3342: public opaq_edge_entry_4
                   3343: public opaq_edge_entry_3
                   3344: public opaq_edge_entry_2
                   3345: public opaq_edge_entry_1
                   3346: public opaq_draw_right_edge_only
                   3347: public opaq_draw_right_edge_only_entry
                   3348: public opaq_draw_both_edges
                   3349: public opaq_check_more_banks
                   3350: public opaq_do_next_bank
                   3351: public special_8_wide_aligned_opaque
                   3352: public s8wa0_init_bank_mapped
                   3353: public s8wao_byte_loop
                   3354: public s8wao_byte_8
                   3355: public s8wao_byte_7
                   3356: public s8wao_byte_6
                   3357: public s8wao_byte_5
                   3358: public s8wao_byte_4
                   3359: public s8wao_byte_3
                   3360: public s8wao_byte_2
                   3361: public s8wao_byte_1
                   3362: public s8wao_map_init_bank
                   3363: public xpar_map_init_bank
                   3364: public xpar_init_bank_mapped
                   3365: public xpar_bank_loop
                   3366: public xpar_scan_loop
                   3367: public xpar_scan_done
                   3368: public do_next_xpar_bank
                   3369: public xpar_high_nibble_F
                   3370: public xpar_high_nibble_E
                   3371: public xpar_high_nibble_D
                   3372: public xpar_high_nibble_C
                   3373: public xpar_high_nibble_B
                   3374: public xpar_high_nibble_8
                   3375: public xpar_high_nibble_6
                   3376: public xpar_high_nibble_5
                   3377: public xpar_high_nibble_4
                   3378: public xpar_high_nibble_7
                   3379: public xpar_high_nibble_3
                   3380: public xpar_high_nibble_A
                   3381: public xpar_high_nibble_2
                   3382: public xpar_high_nibble_9
                   3383: public xpar_high_nibble_1
                   3384: public xpar_high_nibble_0
                   3385: public xpar_low_nibble_F
                   3386: public xpar_low_nibble_E
                   3387: public xpar_low_nibble_D
                   3388: public xpar_low_nibble_C
                   3389: public xpar_low_nibble_B
                   3390: public xpar_low_nibble_8
                   3391: public xpar_low_nibble_6
                   3392: public xpar_low_nibble_5
                   3393: public xpar_low_nibble_4
                   3394: public xpar_low_nibble_7
                   3395: public xpar_low_nibble_3
                   3396: public xpar_low_nibble_A
                   3397: public xpar_low_nibble_2
                   3398: public xpar_low_nibble_9
                   3399: public xpar_low_nibble_1
                   3400: public xpar_low_nibble_0
                   3401: 
                   3402: 
                   3403:         end
                   3404: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.