Annotation of ntddk/src/video/displays/vga/i386/fasttext.asm, revision 1.1

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

unix.superglobalmegacorp.com

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