Annotation of ntddk/src/video/displays/vga/i386/pointer.asm, revision 1.1.1.1

1.1       root        1:         page    ,132
                      2: ;-----------------------------Module-Header-----------------------------;
                      3: ; Module Name:  POINTER.ASM
                      4: ;
                      5: ; This file contains the pointer shape routines required to draw the
                      6: ; pointer shape on the EGA.
                      7: ;
                      8: ; Copyright (c) 1992 Microsoft Corporation
                      9: ;
                     10: ; Exported Functions:   none
                     11: ;
                     12: ; Public Functions:     xyCreateMasks
                     13: ;                       vDrawPointer
                     14: ;                       vYankPointer
                     15: ;
                     16: ; General Description:
                     17: ;
                     18: ;   All display drivers must support a "pointer" for the pointing
                     19: ;   device.  The pointer is a small graphics image which is allowed
                     20: ;   to move around the screen independantly of all other operations
                     21: ;   to the screen, and is normally bound to the location of the
                     22: ;   pointing device.  The pointer is non-destructive in nature, i.e.
                     23: ;   the bits underneath the pointer image are not destroyed by the
                     24: ;   presence of the pointer image.
                     25: ;
                     26: ;   A pointer consists of an AND mask and an XOR mask, which give
                     27: ;   combinations of 0's, 1's, display, or inverse display.
                     28: ;
                     29: ;                   AND XOR | DISPLAY
                     30: ;                   ----------------------
                     31: ;                    0   0  |     0
                     32: ;                    0   1  |     1
                     33: ;                    1   0  |   Display
                     34: ;                    1   1  | Not Display
                     35: ;
                     36: ;   The pointer also has a "hot spot", which is the pixel of the
                     37: ;   pointer image which is to be aligned with the actual pointing
                     38: ;   device location.
                     39: ;
                     40: ;
                     41: ;                 |         For a pointer like this, the hot spot
                     42: ;                 |         would normally be the *, which would
                     43: ;              ---*---      be aligned with the pointing device
                     44: ;                 |         position
                     45: ;                 |
                     46: ;
                     47: ;   The pointer may be moved to any location on the screen, be
                     48: ;   restricted to only a section of the screen, or made invisible.
                     49: ;   Part of the pointer may actually be off the edge of the screen,
                     50: ;   and in such a case only the visible portion of the pointer
                     51: ;   image is displayed.
                     52: ;
                     53: ;
                     54: ;
                     55: ;   Logically, the pointer image isn't part of the physical display
                     56: ;   surface.  When a drawing operation coincides with the pointer
                     57: ;   image, the result is the same as if the pointer image wasn't
                     58: ;   there.  In reality, if the pointer image is part of the display
                     59: ;   surface it must be removed from memory before the drawing
                     60: ;   operation may occur, and redrawn at a later time.
                     61: ;
                     62: ;   This exclusion of the pointer image is the responsibility of
                     63: ;   the display driver.  If the pointer image is part of physical
                     64: ;   display memory, then all output operations must perform a hit
                     65: ;   test to determine if the pointer must be removed from display
                     66: ;   memory, and set a protection rectangle wherein the pointer must
                     67: ;   not be displayed.  The actual pointer image drawing routine
                     68: ;   must honor this protection rectangle by never drawing the
                     69: ;   pointer image within its boundary.
                     70: ;
                     71: ;   This code doesn't distinguish between pointers and icons,
                     72: ;   they both are the same size, 32 x 32, which comes out square.
                     73: ;
                     74: ; Restrictions:
                     75: ;
                     76: ;   All routines herein assume protection either via cli/sti
                     77: ;   or a semephore at higher level code.
                     78: ;
                     79: ;-----------------------------------------------------------------------;
                     80: 
                     81:         .386
                     82: 
                     83: ifndef  DOS_PLATFORM
                     84:         .model  small,c
                     85: else
                     86: ifdef   STD_CALL
                     87:         .model  small,c
                     88: else
                     89:         .model  small,pascal
                     90: endif;  STD_CALL
                     91: endif;  DOS_PLATFORM
                     92: 
                     93:         ASSUME   CS: FLAT, DS: FLAT, SS: FLAT, ES: FLAT
                     94:         assume   FS: NOTHING, GS: NOTHING
                     95: 
                     96:         .xlist
                     97:         include stdcall.inc
                     98:         include i386\egavga.inc
                     99:         include i386\strucs.inc
                    100:         .list
                    101: 
                    102:         PUBLIC  PTR_ROUND_RIGHT         ;Pointer exclusion needs these
                    103:         PUBLIC  PTR_ROUND_LEFT
                    104:         PUBLIC  PTR_WIDTH_BITS
                    105:         PUBLIC  PTR_HEIGHT
                    106: 
                    107: 
                    108: ;-----------------------------------------------------------------------;
                    109: ; The following values allow us to set rounding for cursor exclusion.
                    110: ; These values are applied as an AND mask (for rounding left) and as
                    111: ; an OR mask (for rounding right).
                    112: ;-----------------------------------------------------------------------;
                    113: 
                    114: ROUNDING_SIZE   EQU     8                       ;Round to byte boundaries
                    115:                 .ERRNZ  ROUNDING_SIZE AND 111b  ;Must be at least byte boundary
                    116: PTR_ROUND_RIGHT EQU     ROUNDING_SIZE-1
                    117: PTR_ROUND_LEFT  EQU     -ROUNDING_SIZE
                    118: 
                    119: ;-----------------------------------------------------------------------;
                    120: ; The RECT_DATA structure is used for describing the rectangles
                    121: ; which will be manipulated by this code.  The fields are:
                    122: ;
                    123: ; rd_ptbSave    This is the (X,Y) origin of the given rectangle in
                    124: ;               the save area.
                    125: ;
                    126: ; rd_ptlScreen  This is the (X,Y) origin of the given rectangle on
                    127: ;               the screen.
                    128: ;
                    129: ; rd_sizb       This is the extents of the rectangle.
                    130: ;
                    131: ; rd_ptbWork    This is the (X,Y) origin of the given rectangle in
                    132: ;               the work area.
                    133: ;-----------------------------------------------------------------------;
                    134: 
                    135: ifdef DUPS_ARE_LEGAL
                    136: 
                    137: RECT_DATA       STRUC
                    138: rd_ptbSave      DW      ((SIZE POINTB)/2) DUP (0)
                    139: rd_ptlScreen    DW      ((SIZE POINTL)/2) DUP (0)
                    140: rd_sizb         DW      ((SIZE SIZEB)/2)  DUP (0)
                    141: rd_ptbWork      DW      ((SIZE POINTB)/2) DUP (0)
                    142: RECT_DATA       ENDS
                    143:                 .ERRNZ  SIZE POINTB AND 1
                    144:                 .ERRNZ  SIZE POINTL AND 1
                    145:                 .ERRNZ  SIZE SIZEB  AND 1
                    146: 
                    147: else
                    148: 
                    149: RECT_DATA       STRUC
                    150: rd_ptbSave      dw      0                   ; POINTB
                    151: rd_ptlScreen    dd      0,0                 ; POINTL
                    152: rd_sizb         dw      0                   ; SIZEB
                    153: rd_ptbWork      dw      0                   ; POINTB
                    154: RECT_DATA       ENDS
                    155:                 .ERRNZ  (SIZE POINTB) - 2
                    156:                 .ERRNZ  (SIZE POINTL) - 8
                    157:                 .ERRNZ  (SIZE SIZEB)  - 2
                    158: 
                    159: endif
                    160: 
                    161: 
                    162: 
                    163: ;-----------------------------------------------------------------------;
                    164: ; The POINTER_DATA structure is used for describing the actual pointer's
                    165: ; rectangle.  It also contains clipping information and control flags.
                    166: ; The fields are:
                    167: ;
                    168: ; pd_rd         RECT_DATA structure as defined above
                    169: ;
                    170: ; pd_fb         Flags as follows:
                    171: ;
                    172: ; PD_VALID        1 The rectangle contains valid data.
                    173: ;                 0 The rectangle data is invalid.
                    174: ;
                    175: ; PD_CLIP_BOTTOM  1 Clip the bottom
                    176: ;                 0 No bottom clipping needed
                    177: ;
                    178: ; PD_CLIP_TOP     1 Clip the top
                    179: ;                 0 No top clipping needed
                    180: ;
                    181: ; PD_CLIP_LEFT    1 Clip the lhs
                    182: ;                 0 No lhs clipping needed
                    183: ;
                    184: ; PD_CLIP_RIGHT   1 Clip the rhs
                    185: ;                 0 No rhs clipping needed
                    186: ;-----------------------------------------------------------------------;
                    187: 
                    188: ifdef DUPS_ARE_LEGAL
                    189: 
                    190: POINTER_DATA    STRUC
                    191: pd_rd           DW      ((SIZE RECT_DATA)/2) DUP (0)
                    192: pd_fb           DB      0
                    193:                 DB      0
                    194: POINTER_DATA    ENDS
                    195:                 .ERRNZ  SIZE RECT_DATA AND 1
                    196: 
                    197: else
                    198: 
                    199: POINTER_DATA    struc
                    200: pd_rd           dw      0,0,0,0,0,0,0       ; RECT_DATA
                    201: pd_fb           db      0
                    202:                 db      0
                    203: POINTER_DATA    ends
                    204:                 .ERRNZ  (size POINTER_DATA) - (SIZE RECT_DATA) - 2
                    205: 
                    206: endif
                    207: 
                    208: 
                    209: PD_CLIP_BOTTOM  EQU     10000000b
                    210: PD_CLIP_TOP     EQU     01000000b
                    211: PD_CLIP_RIGHT   EQU     00100000b
                    212: PD_CLIP_LEFT    EQU     00010000b
                    213: PD_VALID        EQU     00001000b
                    214: ;               EQU     00000100b
                    215: ;               EQU     00000010b
                    216: ;               EQU     00000001b
                    217: 
                    218: PD_CLIPPED      EQU     PD_CLIP_BOTTOM OR PD_CLIP_TOP OR PD_CLIP_RIGHT OR PD_CLIP_LEFT
                    219: 
                    220: 
                    221:         .DATA
                    222: 
                    223:         PUBLIC  pdPtr1
                    224:         PUBLIC  pdPtr2
                    225:         PUBLIC  rdFlushX
                    226:         PUBLIC  rdFlushY
                    227:         PUBLIC  rdOverlap
                    228:         PUBLIC  rdReadX
                    229:         PUBLIC  rdReadY
                    230:         PUBLIC  rdWork
                    231: 
                    232: 
                    233: ;       Offsets of locations in the EGA/VGA's address
                    234: ;       space used both to determine and save the state of the EGA/VGA.
                    235: ;
                    236: ;       The actual address within the EGA/VGA's Regen RAM is determined
                    237: ;       at init time, and is based on the number of vertical scans.
                    238: 
                    239:         EXTRN pPtrSave     : DWORD      ;offset from bitmap start of pointer
                    240:         EXTRN pPtrWork     : DWORD      ; work areas
                    241: 
                    242: ; !!! This temp flag is a stupid hack to know if the pointer is color or
                    243: ; !!! mono.  Fix it up
                    244: 
                    245: 
                    246: flPointer   dd      0
                    247: 
                    248: 
                    249: 
                    250: pdPtr1          POINTER_DATA <>         ;Old/New pointer's data
                    251: pdPtr2          POINTER_DATA <>         ;Old/New pointer's data
                    252: rdFlushX        RECT_DATA <>            ;Flush from save area to screen
                    253: rdFlushY        RECT_DATA <>            ;Flush from save area to screen
                    254: rdOverlap       RECT_DATA <>            ;And from save area to work area
                    255: rdReadX         RECT_DATA <>            ;Read from screen to save, xor to work
                    256: rdReadY         RECT_DATA <>            ;Read from screen to save, xor to work
                    257: rdWork          RECT_DATA <>            ;Xor from work to screen
                    258: 
                    259: 
                    260: ;-----------------------------------------------------------------------;
                    261: ; siz?Mask contains the width and height of the working portion of
                    262: ; the current AND and XOR mask.  Use of this allows us to manipulate
                    263: ; less memory when parts of the pointer won't alter the screen image.
                    264: ;-----------------------------------------------------------------------;
                    265: 
                    266: sizbMask        SIZEB   <WORK_WIDTH,PTR_HEIGHT>
                    267: sizlMask        SIZEL   <WORK_WIDTH,PTR_HEIGHT>
                    268: 
                    269: 
                    270: ;-----------------------------------------------------------------------;
                    271: ; sizsMaxDelta is the maximum distance the old and new pointers may
                    272: ; be before they are considered disjoint.
                    273: ;-----------------------------------------------------------------------;
                    274: 
                    275: sizlMaxDelta    SIZEL   <WORK_WIDTH,WORK_HEIGHT>
                    276: 
                    277: 
                    278: ;-----------------------------------------------------------------------;
                    279: ; ptlBotRightClip is the coordinate where rhs or bottom clipping
                    280: ; will first occur.  It is basically the screen width - pointer width.
                    281: ;-----------------------------------------------------------------------;
                    282: 
                    283: ptlBotRightClip POINTL  <0,0>
                    284: 
                    285: 
                    286: ;-----------------------------------------------------------------------;
                    287: ; This is the initial origin in the save buffer.
                    288: ;-----------------------------------------------------------------------;
                    289: 
                    290: ptbInitOrigin   POINTB  <0,0>
                    291: 
                    292: 
                    293: ;-----------------------------------------------------------------------;
                    294: ; ppdOld is the pointer to the old pointer's POINTER_DATA structure
                    295: ;-----------------------------------------------------------------------;
                    296: 
                    297: ppdOld          DD      offset FLAT:pdPtr1
                    298: 
                    299: 
                    300: ;-----------------------------------------------------------------------;
                    301: ; ppdNew is the pointer to the new pointer's POINTER_DATA structure
                    302: ;-----------------------------------------------------------------------;
                    303: 
                    304: ppdNew          DD      offset FLAT:pdPtr2
                    305: 
                    306: 
                    307: ;-----------------------------------------------------------------------;
                    308: ; pAndXor is the pointer to which AND/XOR mask is to be used.   It is
                    309: ; based on the 3 least significant bits of the pointer's X coordinate.
                    310: ; pColor is the pointer to which COLOR mask is to be used.
                    311: ;-----------------------------------------------------------------------;
                    312: 
                    313: pAndXor         DD      -1
                    314: pColor          DD      -1
                    315: 
                    316: 
                    317: ;-----------------------------------------------------------------------;
                    318: ; The following are the masks which make up the pointer image.  There
                    319: ; will be one AND/XOR/COLOR mask pair for each possible alignment.  On
                    320: ; move_pointers call, all the alignments will be generated to save time.
                    321: ;-----------------------------------------------------------------------;
                    322: 
                    323:         public  base_and_masks
                    324:         public  base_xor_masks
                    325:         public  base_clr_masks
                    326: 
                    327: base_and_masks  EQU     THIS BYTE
                    328:                 REPT    (MASK_LENGTH * 8)
                    329:                 DB      ?
                    330:                 ENDM
                    331: 
                    332: base_xor_masks  EQU     THIS BYTE
                    333:                 REPT    (MASK_LENGTH * 8)
                    334:                 DB      ?
                    335:                 ENDM
                    336: 
                    337: base_clr_masks  EQU     THIS BYTE
                    338:                 REPT    (CLR_MASK_LENGTH * 8)
                    339:                 DB      ?
                    340:                 ENDM
                    341: 
                    342: ;-----------------------------------------------------------------------;
                    343: ; pabAndMasks is an array which points to the start of the mask for
                    344: ; each X rotation.  It is indexed into using the low 3 bits of the
                    345: ; pointer's X coordinate.
                    346: ;-----------------------------------------------------------------------;
                    347: 
                    348: pabAndMasks     EQU     THIS DWORD
                    349:                 DD      offset FLAT:base_and_masks+(0*MASK_LENGTH)
                    350:                 DD      offset FLAT:base_and_masks+(1*MASK_LENGTH)
                    351:                 DD      offset FLAT:base_and_masks+(2*MASK_LENGTH)
                    352:                 DD      offset FLAT:base_and_masks+(3*MASK_LENGTH)
                    353:                 DD      offset FLAT:base_and_masks+(4*MASK_LENGTH)
                    354:                 DD      offset FLAT:base_and_masks+(5*MASK_LENGTH)
                    355:                 DD      offset FLAT:base_and_masks+(6*MASK_LENGTH)
                    356:                 DD      offset FLAT:base_and_masks+(7*MASK_LENGTH)
                    357: 
                    358: ;-----------------------------------------------------------------------;
                    359: ; pabClrMasks is an array which points to the start of the mask for
                    360: ; each X rotation.  It is indexed into using the low 3 bits of the
                    361: ; pointer's X coordinate.
                    362: ;-----------------------------------------------------------------------;
                    363: 
                    364: pabClrMasks     EQU     THIS DWORD
                    365:                 DD      offset FLAT:base_clr_masks+(0*CLR_MASK_LENGTH)
                    366:                 DD      offset FLAT:base_clr_masks+(1*CLR_MASK_LENGTH)
                    367:                 DD      offset FLAT:base_clr_masks+(2*CLR_MASK_LENGTH)
                    368:                 DD      offset FLAT:base_clr_masks+(3*CLR_MASK_LENGTH)
                    369:                 DD      offset FLAT:base_clr_masks+(4*CLR_MASK_LENGTH)
                    370:                 DD      offset FLAT:base_clr_masks+(5*CLR_MASK_LENGTH)
                    371:                 DD      offset FLAT:base_clr_masks+(6*CLR_MASK_LENGTH)
                    372:                 DD      offset FLAT:base_clr_masks+(7*CLR_MASK_LENGTH)
                    373: 
                    374: ;-----------------------------------------------------------------------;
                    375: ; The following flags and flag bytes are used to control which
                    376: ; rectangles are used for what.
                    377: ;
                    378: ; fbFlush controls which rectangles are to be copied from the save
                    379: ; area to the screen.  Valid flags are:
                    380: ;
                    381: ;   FB_OLD_PTR, FB_FLUSH_X, FB_FLUSH_Y
                    382: ;
                    383: ;   FB_OLD_PTR is mutually exclusive of all other flags
                    384: ;
                    385: ;
                    386: ; fbAndRead controls which rectangles are to be ANDed into the work
                    387: ; area from the screen or save area, and which rectangles are to be
                    388: ; copied from the screen to the save area.  Valid flags are:
                    389: ;
                    390: ;   FB_NEW_PTR, FB_OVERLAP, FB_READ_X, FB_READ_Y, FB_WORK_RECT,
                    391: ;
                    392: ;   FB_NEW_PTR and FB_WORK_RECT are mutually exclusive of all other
                    393: ;   flags.  Note that FB_OVERLAP doesn't apply when coping into the
                    394: ;   save area.
                    395: ;
                    396: ;
                    397: ; fbXor describes which rectangle is to be XORed from the work area
                    398: ; into the screen.  Valid flags are:
                    399: ;
                    400: ;   FB_NEW_PTR, FB_WORK_RECT
                    401: ;
                    402: ;   FB_NEW_PTR and FB_WORK_RECT are mutually exclusive
                    403: ;-----------------------------------------------------------------------;
                    404: 
                    405: fbFlush         DB      0
                    406: fbAndRead       DB      0
                    407: fbXor           DB      0
                    408: FB_OLD_PTR      EQU     10000000b
                    409: FB_NEW_PTR      EQU     01000000b
                    410: FB_FLUSH_X      EQU     00100000b
                    411: FB_FLUSH_Y      EQU     00010000b
                    412: FB_OVERLAP      EQU     00001000b
                    413: FB_READ_X       EQU     00000100b
                    414: FB_READ_Y       EQU     00000010b
                    415: FB_WORK_RECT    EQU     00000001b
                    416: 
                    417: ; Temporary work buffer.  We copy the masks and color data here before
                    418: ; we decide how to flip them.  !!! Costly use of static space.  Use frame
                    419: 
                    420:                 public  alWorkBuff
                    421: 
                    422: 
                    423: alWorkBuff      EQU     THIS DWORD
                    424:                 REPT    (2 * PTR_HEIGHT)
                    425:                 DD      ?
                    426:                 ENDM
                    427: 
                    428: 
                    429: ; Table of entry points into and_from_screen inner loop
                    430: 
                    431:         align   4
                    432: and_from_screen_entry_table label dword
                    433:         dd      and_from_screen_width_0
                    434:         dd      and_from_screen_width_1
                    435:         dd      and_from_screen_width_2
                    436:         dd      and_from_screen_width_3
                    437:         dd      and_from_screen_width_4
                    438:         dd      and_from_screen_width_5
                    439: 
                    440: 
                    441: ; Table of entry points into and_from_save inner loop
                    442: 
                    443:         align   4
                    444: and_from_save_entry_table label dword
                    445:         dd      and_from_save_width_0
                    446:         dd      and_from_save_width_1
                    447:         dd      and_from_save_width_2
                    448:         dd      and_from_save_width_3
                    449:         dd      and_from_save_width_4
                    450:         dd      and_from_save_width_5
                    451: 
                    452: 
                    453: ; Table of entry points into cps_do_a_pass inner loop
                    454: 
                    455:         align   4
                    456: color_to_screen_entry_table label dword
                    457:         dd      color_to_screen_width_0
                    458:         dd      color_to_screen_width_1
                    459:         dd      color_to_screen_width_2
                    460:         dd      color_to_screen_width_3
                    461:         dd      color_to_screen_width_4
                    462:         dd      color_to_screen_width_5
                    463: 
                    464: ;------------------------------------------------------------------------;
                    465: 
                    466:         .CODE
                    467: 
                    468: _TEXT$01   SEGMENT DWORD USE32 PUBLIC 'CODE'
                    469:            ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
                    470: 
                    471: ;--------------------------Public-Routine-------------------------------;
                    472: ; xyCreateMasks
                    473: ;
                    474: ;   The AND, XOR and COLOR pointer masks are stored in the pointer work
                    475: ;   areas.  The original mask will be pre-rotated for all eight
                    476: ;   possible alignments within a byte.
                    477: ;
                    478: ;   As the pointer is copied, it will be processed to see if it
                    479: ;   can be made narrower.  After it has been copied, it will be
                    480: ;   processed to see if it can be made shorter.
                    481: ;
                    482: ;   The following table indicates how the XOR/AND bitmap interacts with
                    483: ;   the COLOR bitmap for a color system:
                    484: ;
                    485: ;       XOR     AND     COLOR   Result
                    486: ;       1       1       x       invert screen
                    487: ;       0       0       x       use x
                    488: ;       0       1       x       transparent
                    489: ;       1       0       x       use x
                    490: ;
                    491: ;   From the table, we observe that when the AND bits are on, the
                    492: ;   corresponding COLOR bits are irrelevant.  We preprocess the
                    493: ;   COLOR bitmap to mask off these bits.
                    494: ;
                    495: ;   When drawing the color pointer, we do the following steps:
                    496: ;       1. XOR the destination with XOR mask.
                    497: ;       2. AND the destination with AND mask.  Note the zero bits
                    498: ;          would mask off the destination to prepare for the COLOR mask.
                    499: ;       3. OR the destination with the COLOR mask.  Note it does not
                    500: ;          affect the inverted or transparent bits since we have masked
                    501: ;          off the corresponding COLOR bits during preprocessing.
                    502: ;
                    503: ; Entry:
                    504: ;
                    505: ; Returns:
                    506: ;       AX = width in pels for exclusion hit test
                    507: ;       DX = height in scans for exclusion hit test
                    508: ; Error Returns:
                    509: ;       None
                    510: ; Registers Preserved:
                    511: ;       BP
                    512: ; Registers Destroyed:
                    513: ;       AX,BX,CX,DX,SI,DI,FLAGS
                    514: ; Calls:
                    515: ;       create_masks_1_thru_7
                    516: ;
                    517: ;-----------------------------------------------------------------------;
                    518: 
                    519: cProc   xyCreateMasks,24,<  \
                    520:         USES esi edi ebx,   \
                    521:         ppdev:PTR,          \
                    522:         pBitsAndXor:PTR,    \
                    523:         pBitsColor:PTR,     \
                    524:         cyHeight:DWORD,     \
                    525:         pulXlate:DWORD,     \
                    526:         wFlags:WORD         >
                    527: 
                    528:         local   cyScreen:dword          ;height of bitmap in scans
                    529:         local   lNextScan:dword         ;width of bitmap in bytes
                    530:         local   ajColorBits[PTR_WIDTH*PTR_HEIGHT*4]:byte
                    531:         local   aulXlate[16]:dword
                    532: 
                    533:         cld
                    534: 
                    535:         mov     ecx,ppdev
                    536:         mov     eax,[ecx].PDEV_sizlSurf.sizl_cy
                    537:         mov     cyScreen,eax
                    538:         mov     ecx,[ecx].PDEV_pdsurf
                    539:         mov     eax,[ecx].dsurf_lNextScan
                    540:         mov     lNextScan,eax
                    541: 
                    542:         cmp     pBitsColor,0
                    543:         jne     short xycm_have_color
                    544: ; Copy the AND/XOR mask into the work buffer
                    545: 
                    546:         mov     esi,pBitsAndXor
                    547:         mov     ecx,cyHeight
                    548:         mov     bx,wFlags
                    549:         shl     ecx,1
                    550:         mov     edi,offset FLAT:alWorkBuff
                    551:         rep movsd                       ;copy AND mask
                    552:         jmp     short xycm_continue
                    553: 
                    554: xycm_have_color:
                    555: 
                    556: ; If a color translation vector was given, generate the new bit
                    557: ; conversion array
                    558: 
                    559:         mov     eax,offset FLAT:aulDefBitMapping
                    560:         cld
                    561:         mov     esi,pulXlate
                    562:         or      esi,esi
                    563:         jz      have_mapping_array
                    564:         lea     edi,aulXlate
                    565:         mov     ecx,16
                    566: create_next_bit_mapping:
                    567:         lodsd
                    568:         mov     eax,aulDefBitMapping[eax*4]
                    569:         stosd
                    570:         dec     ecx
                    571:         jnz     create_next_bit_mapping
                    572:         lea     eax,[edi][-16*4]
                    573: have_mapping_array:
                    574:         mov     pulXlate,eax
                    575: 
                    576: ; Copy the AND mask into the work buffer
                    577: 
                    578:         mov     edi,offset FLAT:alWorkBuff
                    579:         test    wFlags,PTRI_INVERT      ;are masks backwards?
                    580:         jz      @F                      ;  NO
                    581:         mov     edi,offset FLAT:alWorkBuff + (4*PTR_HEIGHT)
                    582: @@:
                    583:         mov     esi,pBitsAndXor
                    584:         mov     ecx,cyHeight
                    585:         rep movsd                       ;copy AND mask
                    586: 
                    587: ; later on we will flip the AND and XOR masks, so we have to mix them
                    588: ; up now else there will be problems later.
                    589: 
                    590:         mov     esi,pBitsColor                  ;Source color bits
                    591:         lea     edi,ajColorBits                 ;Where to store color
                    592:         mov     ecx,cyHeight
                    593:         mov     dx,wFlags
                    594:         push    ebp
                    595:         mov     ebp,pulXlate
                    596:         call    vConvertDIBPointer
                    597:         pop     ebp
                    598: 
                    599: xycm_continue:
                    600:         mov     ebx,cyHeight
                    601:         mov     dx,wFlags
                    602:         cCall   vCopyMasks              ;Pad and maybe flip masks
                    603: 
                    604: ;-----------------------------------------------------------------------;
                    605: ; The image we are copying is PTR_WIDTH bytes wide.  We must add an
                    606: ; extra byte to make it WORK_WIDTH wide.  The byte we add will depends
                    607: ; on whether this is the AND or the XOR mask.  For an AND mask, we add
                    608: ; an FF byte on the end of each scan.  For an XOR mask, we add a 00
                    609: ; byte on the end of each scan.  For the COLOR mask, we add a 00 byte on
                    610: ; the end of each scan of all planes.  These bytes won't alter anything
                    611: ; on the screen.
                    612: ;-----------------------------------------------------------------------;
                    613: 
                    614:         mov     esi,offset FLAT:alWorkBuff ;ESI --> AND/XOR mask
                    615: 
                    616: ;-----------------------------------------------------------------------;
                    617: ; Copy the AND mask over.  As we copy it, accumulate the value of
                    618: ; each column of the mask.  If the entire column is FF, we may be
                    619: ; able to discard it.
                    620: ;-----------------------------------------------------------------------;
                    621: 
                    622:         mov     edi, offset FLAT:base_and_masks
                    623:         mov     ecx, PTR_HEIGHT         ;Set height for move
                    624:         mov     ebx, 0FFFFFFFFh         ;Accumulate mask columns
                    625: 
                    626: move_next_and_mask_scan:
                    627:         lodsd                           ;Move explicit part
                    628:         stosd
                    629:         and     ebx, eax
                    630:         mov     al, 0FFh
                    631:         stosb
                    632:         .ERRNZ  PTR_WIDTH-4
                    633:         .ERRNZ  WORK_WIDTH-5
                    634:         loop    move_next_and_mask_scan
                    635:         push    ebx                     ;Save AND column mask
                    636:         mov     edx, offset FLAT:base_and_masks
                    637:         mov     ecx, (MASK_LENGTH*7)/(WORK_WIDTH*2)
                    638:         .ERRNZ  (MASK_LENGTH*7) mod (WORK_WIDTH*2)
                    639:         cCall   create_masks_1_thru_7
                    640: 
                    641: ;-----------------------------------------------------------------------;
                    642: ; Copy the XOR mask over.  As we copy it, accumulate the value of
                    643: ; each column of the mask.  If the entire column is 00, we may be
                    644: ; able to discard it.
                    645: ;-----------------------------------------------------------------------;
                    646: 
                    647:         mov     edi, offset FLAT:base_xor_masks
                    648:         mov     ecx, PTR_HEIGHT         ;Set height for move
                    649:         xor     ebx, ebx                ;Accumulate columns of the mask
                    650: 
                    651: move_next_xor_mask_scan:
                    652:         lodsd                           ;Move explicit part
                    653:         stosd
                    654:         or      ebx, eax
                    655:         xor     al, al
                    656:         stosb
                    657:         .ERRNZ  PTR_WIDTH-4
                    658:         .ERRNZ  WORK_WIDTH-5
                    659:         loop    move_next_xor_mask_scan
                    660:         push    ebx
                    661:         mov     edx, offset FLAT:base_xor_masks
                    662:         mov     ecx, (MASK_LENGTH*7)/(WORK_WIDTH*2)
                    663:         .ERRNZ  (MASK_LENGTH*7) mod (WORK_WIDTH*2)
                    664:         cCall   create_masks_1_thru_7
                    665: 
                    666: ;-----------------------------------------------------------------------;
                    667: ; The masks have been copied.  Compute the number of columns which can
                    668: ; be discarded.  To discard a column, all bits of the AND mask for that
                    669: ; column must be 1, and all bits of the XOR mask for the column must be
                    670: ; 0.  Since we work with bytes in this code, this must be true for an
                    671: ; entire byte.
                    672: ;
                    673: ; Also note that the columns must be processed right to left.  We cannot
                    674: ; throw out a middle column if its neighbors contain data.
                    675: ;-----------------------------------------------------------------------;
                    676: 
                    677:         ;AND mask, EAX[0] = byte 1, EAX[1] = byte 2
                    678:         ;AND mask, EAX[2] = byte 3, EAX[3] = byte 4
                    679:         ;XOR mask, EBX[0] = byte 1, EBX[1] = byte 2
                    680:         ;XOR mask, EBX[2] = byte 3, EBX[3] = byte 4
                    681: 
                    682:         pop     ebx                     ;EBX XOR mask
                    683:         pop     eax                     ;EAX AND mask
                    684: 
                    685:         not     eax
                    686:         or      eax, ebx                ;Discard only if both are zero!
                    687: 
                    688:         mov     ebx, WORK_WIDTH
                    689:         mov     edx, PTR_HEIGHT         ;assume full mask
                    690:         xor     ecx, ecx
                    691:                                         ;check wFlags
                    692:         test    wFlags, PTRI_ANIMATE
                    693:         jnz     mp_have_sizes
                    694: 
                    695: ; !!! Until conversion of pointer images is handled via bitblt, always
                    696: ; !!! treat color cursors as full size
                    697:         cmp     pBitsColor,0            ;!!!
                    698:         jne     mp_have_sizes           ;!!!
                    699: 
                    700:         mov     edx,eax                 ;DX = bytes 1 and 2
                    701:         shr     eax,16                  ;AX = bytes 3 and 4
                    702:         or      ah,ah                   ;Discard 4th byte of mask?
                    703:         jnz     @F                      ;  No
                    704:         dec     ebx
                    705:         or      al,al
                    706:         jnz     @F
                    707:         dec     ebx
                    708:         or      dh,dh
                    709:         jnz     @F
                    710:         dec     ebx
                    711:         or      dl,dl
                    712:         jz      move_pointers_done      ;AX = DX = 0 for return codes
                    713: @@:
                    714: 
                    715: ;-----------------------------------------------------------------------;
                    716: ; Compute the number of rows which can be discarded off the bottom.
                    717: ; To discard a row, all bits of the AND mask for that row must be a
                    718: ; 1, and all bits of the XOR mask for that row must be 0.
                    719: ;-----------------------------------------------------------------------;
                    720: 
                    721:         .ERRNZ  PTR_WIDTH AND 1         ;Must be a word multiple
                    722: 
                    723:         dec     esi                     ;Post decremnent, not pre decrement
                    724:         dec     esi
                    725:         lea     edi, [esi][-PTR_WIDTH*PTR_HEIGHT] ;Last word of AND mask
                    726:         mov     ecx, (PTR_WIDTH/2)*PTR_HEIGHT
                    727:         mov     ax, 0FFFFh              ;Processing AND mask
                    728:         std
                    729:         repe    scasw
                    730:         mov     edx, ecx                ;Save count
                    731:         mov     edi, esi                ;--> XOR mask
                    732:         mov     ecx, (PTR_WIDTH/2)*PTR_HEIGHT
                    733:         xor     eax, eax                ;Processing XOR mask
                    734:         repe    scasw
                    735:         cld                             ;Take care of this while we remember
                    736:         cmp     ecx, edx                ;Want |cx| to be the largest
                    737:         ja      @F
                    738:         xchg    ecx, edx
                    739: @@:
                    740: ;-----------------------------------------------------------------------;
                    741: ;  CX   >> 1   +1
                    742: ;
                    743: ;  63    31    32    1st word did not match, don't chop any scans
                    744: ;  62    31    32    2nd word did not match, don't chop any scans
                    745: ;  61    30    31    3rd word did not match, chop 1 scan
                    746: ;  60    30    31    4th word did not match, chop 1 scan
                    747: ;-----------------------------------------------------------------------;
                    748: 
                    749:         .ERRNZ  PTR_WIDTH-4
                    750: 
                    751:         shr     ecx, 1
                    752:         inc     ecx                     ;ECX = working height
                    753:         mov     edx, PTR_HEIGHT
                    754:         sub     edx, ecx                ;EDX = # scans chopped off bottom
                    755:         xchg    ecx, edx                ;Height in DX for returning
                    756: 
                    757: ; EBX = working width of the pointer image in bytes.  ECX = amount to
                    758: ; chop of the bottom of the pointer image.  EDX = working height of
                    759: ; the pointer image.
                    760: 
                    761: mp_have_sizes:
                    762:         mov     eax, ebx
                    763:         mov     sizlMask.sizl_cx, eax
                    764:         mov     sizlMaxDelta.sizl_cx, eax
                    765:         mov     ah, dl
                    766:         mov     sizbMask, ax
                    767: 
                    768:         .ERRNZ  sizb_cy-sizb_cx-1
                    769: 
                    770:         mov     eax, edx
                    771:         mov     sizlMask.sizl_cy, eax
                    772:         mov     sizlMaxDelta.sizl_cy, eax
                    773:         neg     eax
                    774:         add     eax, cyScreen
                    775:         mov     ptlBotRightClip.ptl_y, eax
                    776:         mov     eax, lNextScan
                    777:         sub     eax, ebx
                    778:         mov     ptlBotRightClip.ptl_x, eax
                    779:         shr     ecx, 1
                    780:         mov     eax, WORK_WIDTH
                    781:         sub     eax, ebx
                    782:         shr     eax, 1
                    783:         mov     ah, cl
                    784:         mov     ptbInitOrigin, ax
                    785: 
                    786:         .ERRNZ  ptb_y-ptb_x-1
                    787: 
                    788:         mov     eax, ebx
                    789:         dec     eax
                    790:         shl     eax, 3                  ;Bit count is needed
                    791: 
                    792:         shl     edx, 16                 ;Return value in upper word of EAX
                    793:         or      eax, edx                ; is cyPointer, lower word of EAX
                    794:         push    eax                     ; is cxPointer.
                    795: 
                    796: ;-----------------------------------------------------------------------;
                    797: ; Finally, copy the COLOR mask over.  As we copy it, mask off the
                    798: ; corresponding AND bits in the COLOR mask since we do not use that
                    799: ; color bit if the AND bit is on.
                    800: ;
                    801: ;       XOR     AND     COLOR
                    802: ;       1       1       invert screen
                    803: ;       0       0       use color
                    804: ;       0       1       transparent
                    805: ;       1       0       use color
                    806: ;
                    807: ;-----------------------------------------------------------------------;
                    808: 
                    809:         mov     ecx, pBitsColor
                    810:         jecxz   move_color_pointer_done ;pBitsColor was set to null
                    811:         lea     esi, ajColorBits
                    812:         mov     edi, offset FLAT:base_clr_masks
                    813:         push    ebp                     ;Need extra loop counter
                    814:         mov     ebp, BITS_PEL
                    815: 
                    816: move_next_color_mask_plane:
                    817:         mov     ecx, PTR_HEIGHT         ;Set height for move
                    818:         mov     ebx, offset FLAT:base_and_masks
                    819:         sub     ebx, edi                ;make it relative
                    820: 
                    821: move_next_color_mask_scan:
                    822: ifdef WITH_AND_MASK
                    823:         lodsw                           ;Copy a scan from the current plane
                    824:         mov     dx, [ebx][edi]          ;Mask off the corresponding AND bits
                    825:         not     dx
                    826:         and     ax, dx
                    827:         stosw
                    828:         lodsw
                    829:         mov     dx,  [ebx][edi]
                    830:         not     dx
                    831:         and     ax, dx
                    832:         stosw
                    833: else
                    834:         movsd
                    835: endif
                    836:         xor     al, al
                    837:         stosb
                    838: 
                    839:         .ERRNZ  PTR_WIDTH-4
                    840:         .ERRNZ  WORK_WIDTH-5
                    841: 
                    842:         add     esi, (BITS_PEL-1)*PTR_WIDTH
                    843:         loop    move_next_color_mask_scan
                    844:         sub     esi, (BITS_PEL*PTR_WIDTH*PTR_HEIGHT)-PTR_WIDTH
                    845:         dec     ebp
                    846:         jnz     move_next_color_mask_plane
                    847:         pop     ebp                     ;Restore register
                    848: 
                    849:         mov     edx, offset FLAT:base_clr_masks
                    850:         mov     ecx, (CLR_MASK_LENGTH*7)/(WORK_WIDTH*2)
                    851: 
                    852:         .ERRNZ  (CLR_MASK_LENGTH*7) MOD (WORK_WIDTH*2)
                    853: 
                    854:         cCall   create_masks_1_thru_7
                    855: 
                    856: move_color_pointer_done:
                    857: 
                    858:         pop     eax                     ;return results in EAX
                    859: 
                    860: move_pointers_done:
                    861: mp_exit:
                    862:         cRet    xyCreateMasks
                    863: 
                    864: endProc xyCreateMasks
                    865: 
                    866: ;-------------------------Private-Routine-------------------------------;
                    867: ; Copy the masks to the work buffer and adjust for use.  Two things may
                    868: ; need to be done:
                    869: ;
                    870: ;   1) The masks could be inverted.
                    871: ;   2) The masks may need to be padded out
                    872: ;
                    873: ; Entry:
                    874: ;       EBX     = number of scan lines in each mask
                    875: ;        DX     = flags (PTRI_INVERT)
                    876: ;
                    877: ; Returns:
                    878: ;       None
                    879: ;
                    880: ; Error Returns:
                    881: ;       None
                    882: ;
                    883: ;-----------------------------------------------------------------------;
                    884: 
                    885: cProc   vCopyMasks
                    886:         mov     ecx,ebx                 ;Needed for padding calculations
                    887:         test    dx,PTRI_INVERT          ;are masks backwards?
                    888:         jz      copy_no_flip
                    889: 
                    890: ; This is really annoying.  Not only are the masks inverted, but they
                    891: ; are stored in the wrong order.  First get the AND and XOR masks into
                    892: ; the correct order.
                    893: 
                    894:         mov     ecx,PTR_HEIGHT
                    895:         mov     esi,offset FLAT:alWorkBuff
                    896:         mov     edi,offset FLAT:alWorkBuff + PTR_HEIGHT * 4
                    897: 
                    898: @@:
                    899:         mov     eax,[esi]
                    900:         xchg    [edi],eax
                    901:         mov     [esi],eax
                    902:         add     esi,4
                    903:         add     edi,4
                    904:         loop    @B
                    905: 
                    906: ; Next, flip them so they are right-side up.
                    907: 
                    908:         mov     ecx,ebx
                    909:         mov     esi,offset FLAT:alWorkBuff
                    910:         cCall   vFlipMask               ;flip AND mask
                    911: 
                    912:         mov     ecx,ebx
                    913:         mov     esi,offset FLAT:alWorkBuff + PTR_HEIGHT * 4
                    914:         cCall   vFlipMask               ;flip XOR mask
                    915: 
                    916: ; Now pad out the masks so no junk appears on the screen
                    917: 
                    918: copy_no_flip:
                    919: 
                    920:         mov     eax,0FFFFFFFFh          ;pad AND mask
                    921:         mov     ecx,PTR_HEIGHT
                    922:         sub     ecx,ebx
                    923:         mov     edi,offset FLAT:alWorkBuff
                    924:         lea     edi,[edi+4*ebx]
                    925:         rep stosd
                    926: 
                    927:         xor     eax,eax                 ;pad XOR mask
                    928:         mov     ecx,PTR_HEIGHT
                    929:         sub     ecx,ebx
                    930:         mov     edi,offset FLAT:alWorkBuff + PTR_HEIGHT * 4
                    931:         lea     edi,[edi+4*ebx]
                    932:         rep stosd
                    933: 
                    934:         cRet    vCopyMasks
                    935: 
                    936: endProc vCopyMasks
                    937: 
                    938: ;-------------------------Private-Routine-------------------------------;
                    939: ; Flip the scans in the buffer
                    940: ;
                    941: ; Entry:
                    942: ;       ESI --> start of first scan line
                    943: ;       ECX     = number of scan lines
                    944: ;
                    945: ; Returns:
                    946: ;       None
                    947: ;
                    948: ; Error Returns:
                    949: ;       None
                    950: ;
                    951: ;-----------------------------------------------------------------------;
                    952: 
                    953: cProc   vFlipMask
                    954:         lea     edi,[esi+4*ecx]
                    955:         shr     ecx,1
                    956: 
                    957: flip_next_scan:
                    958:         sub     edi,4                   ;decrement target pointer
                    959: 
                    960:         mov     eax,[esi]               ;Load
                    961:         xchg    [edi],eax               ;Swap
                    962:         mov     [esi],eax               ;Save
                    963: 
                    964:         add     esi,4                   ;increment source pointer
                    965: 
                    966:         loop    flip_next_scan
                    967: 
                    968:         cRet    vFlipMask
                    969: 
                    970: endProc vFlipMask
                    971: 
                    972: page
                    973: 
                    974: ;--------------------------Public-Routine-------------------------------;
                    975: ; create_masks_1_thru_7
                    976: ;
                    977: ; The pointer shape has been copied into our memory.  Now pre-rotate
                    978: ; the pointer for all the different alignments.  Simply put:
                    979: ;
                    980: ;                 pointer image              fill byte
                    981: ;
                    982: ;       |ABCDEFGH|IJKLMNOP|QRSTUVWX|YZabcdef|00000000|
                    983: ;
                    984: ;  becomes this for (x mod 8) = 1
                    985: ;
                    986: ;       |0ABCDEFG|HIJKLMNO|PQRSTUVW|XYZabcde|f0000000|
                    987: ;
                    988: ;  and this for (x mod 8) = 2
                    989: ;
                    990: ;       |00ABCDEF|GHIJKLMN|OPQRSTUV|WXYZabcd|ef000000|
                    991: ;
                    992: ; Entry:
                    993: ;       EDI --> first byte of mask for phase alignment 1
                    994: ;       EDX --> first byte of mask for phase alignment 0
                    995: ;       ECX     =  (mask length * 7) / (WORK_WIDTH * 2)
                    996: ;       AL      =  fill value (00 or FF)
                    997: ; Returns:
                    998: ;       None
                    999: ; Error Returns:
                   1000: ;       None
                   1001: ; Registers Preserved:
                   1002: ;       BX,SI,BP
                   1003: ; Registers Destroyed:
                   1004: ;       AX,CX,DX,DI
                   1005: ; Calls:
                   1006: ;       none
                   1007: ;
                   1008: ;-----------------------------------------------------------------------;
                   1009: 
                   1010: cProc   create_masks_1_thru_7
                   1011: 
                   1012: ; Since the masks are contiguous, we can do it as one very long loop,
                   1013: ; where the results of rotating the previous mask by one becomes the
                   1014: ; source for the next rotate by one.
                   1015: 
                   1016:         xchg    esi, edx
                   1017:         add     al, al                  ;Set initial 'C' value
                   1018: 
                   1019: rotate_next_two_scans:
                   1020:         lodsw
                   1021:         rcr     al, 1
                   1022:         rcr     ah, 1
                   1023:         stosw
                   1024: 
                   1025:         lodsw
                   1026:         rcr     al, 1
                   1027:         rcr     ah, 1
                   1028:         stosw
                   1029: 
                   1030:         lodsw
                   1031:         rcr     al, 1
                   1032:         rcr     ah, 1
                   1033:         stosw
                   1034: 
                   1035:         lodsw
                   1036:         rcr     al, 1
                   1037:         rcr     ah, 1
                   1038:         stosw
                   1039: 
                   1040:         lodsw
                   1041:         rcr     al, 1
                   1042:         rcr     ah, 1
                   1043:         stosw
                   1044: 
                   1045:         loop    rotate_next_two_scans
                   1046: 
                   1047:         .ERRNZ  (WORK_WIDTH*2)-10
                   1048: 
                   1049:         xchg    esi, edx
                   1050: 
                   1051:         cRet    create_masks_1_thru_7
                   1052: 
                   1053: endProc create_masks_1_thru_7
                   1054: page
                   1055: 
                   1056: ;--------------------------Public-Routine-------------------------------;
                   1057: ; vYankPointer
                   1058: ;
                   1059: ;   Move the pointer off the right edge of the screen
                   1060: ;
                   1061: ; Returns:
                   1062: ;       per vDrawPointer
                   1063: ; Error Returns:
                   1064: ;       per vDrawPointer
                   1065: ; Registers Preserved:
                   1066: ;       per vDrawPointer
                   1067: ; Registers Destroyed:
                   1068: ;       per vDrawPointer
                   1069: ; Calls:
                   1070: ;       per vDrawPointer
                   1071: ; Restrictions:
                   1072: ;       per vDrawPointer
                   1073: ;
                   1074: ;-----------------------------------------------------------------------;
                   1075: 
                   1076: cProc   vYankPointer,8,<    \
                   1077:         ppdev:ptr PDEV,     \
                   1078:         flPtr:DWORD         >
                   1079: 
                   1080:         mov     eax,ppdev
                   1081:         cCall   vDrawPointer,<eax,[eax].PDEV_sizlsurf.sizl_cx, \
                   1082:                               [eax].PDEV_sizlsurf.sizl_cy,flPtr>
                   1083: yp_exit:
                   1084:         cRet    vYankPointer
                   1085: 
                   1086: endProc vYankPointer
                   1087: 
                   1088: page
                   1089: 
                   1090: ;--------------------------Public-Routine-------------------------------;
                   1091: ; vDrawPointer
                   1092: ;
                   1093: ;   The pointer shape is drawn on the screen at the given coordinates.
                   1094: ;   If it currently is displayed on the screen, it will be removed
                   1095: ;   from the old location first.
                   1096: ;
                   1097: ; Entry:
                   1098: ; Returns:
                   1099: ;       None
                   1100: ; Error Returns:
                   1101: ;       None
                   1102: ; Registers Preserved:
                   1103: ;       BP
                   1104: ; Registers Destroyed:
                   1105: ;       AX,BX,CX,DX,SI,DI,FLAGS
                   1106: ; Calls:
                   1107: ;       compute_rects
                   1108: ;       clip_rects
                   1109: ;       and_into_work
                   1110: ;       copy_things_around
                   1111: ;       xor_to_screen
                   1112: ;       color_pointer_to_screen
                   1113: ; Restrictions:
                   1114: ;       None
                   1115: ;
                   1116: ;-----------------------------------------------------------------------;
                   1117: 
                   1118: cProc   vDrawPointer,16,<   \
                   1119:         USES esi edi ebx,   \
                   1120:         ppdev:ptr PDEV,     \
                   1121:         ptlX:DWORD,         \
                   1122:         ptlY:DWORD,         \
                   1123:         flPtr:DWORD         >
                   1124: 
                   1125:         local   lNextScan :dword        ;width of bitmap in bytes
                   1126:         local   ulNextSrcScan :dword    ;offset to next source scan line
                   1127:         local   jPostWrapWidth :dword   ;post-wrap width
                   1128:         local   pSaveAddr :dword        ;virtual address of save area
                   1129:         local   jSaveSourceXY :dword    ;X and Y coordinates of source point in
                   1130:                                         ; save area
                   1131:         local   jWorkSourceXY :dword    ;X and Y coordinates of source point in
                   1132:                                         ; work area
                   1133:         local   jNextSaveSourceY :dword ;Y coordinate of start source point in
                   1134:                                         ; save area for next bank
                   1135:         local   jNextWorkSourceY :dword ;Y coordinate of start source point in
                   1136:                                         ; work area for next bank
                   1137:         local   pWorkingSave :dword     ;save area virtual address
                   1138:         local   ulScanMinusWorkWidth :dword ;distance to next scan, minus the
                   1139:                                             ; width of the work area
                   1140:         local   ulCurrentTopScan :dword ;top scan line to which to draw in
                   1141:                                         ; current bank
                   1142:         local   jScansInBank :dword     ;# of scan to do in current bank
                   1143:         local   cjTotalScans :dword     ;# of scans left in operation
                   1144:         local   ulPtrBankScan :dword    ;last scan line in pointer work bank
                   1145:         local   pdsurf :ptr DEVSURF     ;pointer to surface structure to which
                   1146:                                         ; we're drawing
                   1147:                                         ;variables used by cps_do_a_pass
                   1148:         local   ulDeltaScreen :dword    ;offset from one scan to next
                   1149:         local   ulOffsetSave :dword     ;offset in save area
                   1150:         local   ulOffsetMask :dword     ;offset within mask
                   1151:         local   iPlaneMask :dword
                   1152:                                         ;variables used by
                   1153:                                         ; color_pointer_to_screen
                   1154:         local   pDest :dword            ;pointer to destination address
                   1155:         local   prclSource :dword       ;pointer to source rectangle
                   1156:         local   cyScreen :dword         ;height of screen in scan lines
                   1157: 
                   1158: ;-----------------------------------------------------------------------;
                   1159: 
                   1160:         cld
                   1161: 
                   1162:         mov     ecx,ppdev
                   1163:         mov     eax,[ecx].PDEV_sizlSurf.sizl_cy
                   1164:         mov     cyScreen,eax
                   1165: 
                   1166:         mov     ecx,[ecx].PDEV_pdsurf
                   1167:         mov     pdsurf,ecx              ;pointer to target surface
                   1168: 
                   1169:         mov     eax,[ecx].dsurf_ulPtrBankScan
                   1170:         mov     ulPtrBankScan,eax       ;last scan line in pointer work bank
                   1171: 
                   1172:         mov     eax,[ecx].dsurf_lNextScan
                   1173:         mov     lNextScan,eax           ;width of bitmap
                   1174: 
                   1175:         mov     eax, flPtr
                   1176:         mov     flPointer,eax           ;save flags
                   1177:         mov     edi, ppdNew             ;--> new pointer's data goes here
                   1178:         mov     esi, ppdOld             ;--> old pointer's data
                   1179:         mov     eax, ptlX               ;EAX = ptlX
                   1180:         mov     ebx, eax
                   1181:         and     ebx, 7
                   1182:         mov     edx, pabAndMasks[ebx * 4]
                   1183:         mov     pAndXor, edx
                   1184:         mov     edx, pabClrMasks[ebx * 4]
                   1185:         mov     pColor, edx
                   1186:         mov     ebx, PD_VALID           ;Assume visible
                   1187:         sar     eax, 3                  ;Compute starting byte address (set 'S')
                   1188:         mov     [edi].pd_rd.rd_ptlScreen.ptl_x, eax
                   1189: 
                   1190: ;-----------------------------------------------------------------------;
                   1191: ; Compute any X clipping parameters for the new pointer image.
                   1192: ;-----------------------------------------------------------------------;
                   1193: 
                   1194:         js      clip_lhs_of_pointer     ;If X is negative, lhs clipping needed
                   1195:         sub     eax, ptlBotRightClip.ptl_x
                   1196:         jle     done_x_clipping
                   1197:         mov     bh,PD_CLIP_RIGHT        ;EAX = amount to clip off rhs
                   1198:         jmp     finish_x_clip
                   1199: 
                   1200: clip_lhs_of_pointer:
                   1201:         neg     eax                     ;Want |eax|
                   1202:         mov     bh, PD_CLIP_LEFT
                   1203: 
                   1204: finish_x_clip:
                   1205:         cmp     eax, sizlMask.sizl_cx   ;Width of pointer in bytes
                   1206:         jge     not_visible             ;Clipped away too much
                   1207:         or      bl, bh
                   1208: done_x_clipping:
                   1209: 
                   1210: ;-----------------------------------------------------------------------;
                   1211: ; Compute any Y clipping parameters for the new pointer image.
                   1212: ;-----------------------------------------------------------------------;
                   1213: 
                   1214:         mov     eax, ptlY
                   1215:         mov     [edi].pd_rd.rd_ptlScreen.ptl_y, eax
                   1216:         or      eax, eax
                   1217:         js      clip_top_of_pointer     ;If Y is negative, top clipping needed
                   1218:         sub     eax, ptlBotRightClip.ptl_y
                   1219:         jle     done_y_clipping
                   1220:         mov     bh, PD_CLIP_BOTTOM      ;AX = amount to clip off bottom
                   1221:         jmp     finish_y_clip
                   1222: 
                   1223: 
                   1224: ;-----------------------------------------------------------------------;
                   1225: ; not_visible - the pointer will be totally off the screen.  All we
                   1226: ; have to do is to determine if any part of the old pointer is visible
                   1227: ; and remove it if so.
                   1228: ;-----------------------------------------------------------------------;
                   1229: 
                   1230: not_visible:
                   1231:         test    [esi].pd_fb, PD_VALID
                   1232:         jz      draw_pointer_exit       ;No new, no old
                   1233:         xor     eax, eax
                   1234:         mov     [edi].pd_fb, al         ;Clear PD_VALID flag, clipping flags
                   1235:         mov     WORD PTR fbAndRead, ax  ;Nothing to read/and/xor
                   1236: 
                   1237:         .ERRNZ  fbXor-fbAndRead-1
                   1238: 
                   1239:         mov     fbFlush, FB_OLD_PTR     ;Write old to screen
                   1240:         jmp     rectangles_been_computed
                   1241: 
                   1242: 
                   1243: ;-----------------------------------------------------------------------;
                   1244: ; Continue with Y clipping
                   1245: ;-----------------------------------------------------------------------;
                   1246: 
                   1247: clip_top_of_pointer:
                   1248:         neg     eax                     ;Want |eax|
                   1249:         mov     bh,PD_CLIP_TOP
                   1250: 
                   1251: finish_y_clip:
                   1252:         cmp     eax, sizlMask.sizl_cy   ;Height of pointer in scans
                   1253:         jge     not_visible             ;Clipped away too much
                   1254:         or      bl, bh
                   1255: 
                   1256: done_y_clipping:
                   1257:         mov     [edi].pd_fb, bl         ;Set clipping flags and show valid
                   1258: 
                   1259: ;-----------------------------------------------------------------------;
                   1260: ; It looks like some portion of the pointer image will be visible.
                   1261: ; Initialize some of the new pointer's POINTER_DATA structure.
                   1262: ;-----------------------------------------------------------------------;
                   1263: 
                   1264:         mov     ax, sizbMask            ;ptbSave will be set by compute_rects
                   1265:         mov     [edi].pd_rd.rd_sizb, ax
                   1266: 
                   1267:         .ERRNZ  (SIZE SIZEB) - 2
                   1268: 
                   1269:         xor     ax, ax
                   1270:         mov     [edi].pd_rd.rd_ptbWork, ax
                   1271: 
                   1272:         .ERRNZ  (SIZE POINTB) - 2
                   1273: 
                   1274: ;-----------------------------------------------------------------------;
                   1275: ; Compute the rectangles describing how things overlap and then clip
                   1276: ; them.
                   1277: ;-----------------------------------------------------------------------;
                   1278: 
                   1279:         call    compute_rects
                   1280: rectangles_been_computed:
                   1281: 
                   1282: ;-----------------------------------------------------------------------;
                   1283: ; Set WRITE mode of EGA/VGA
                   1284: ;-----------------------------------------------------------------------;
                   1285: 
                   1286:         mov     dx, EGA_BASE + GRAF_ADDR
                   1287:         mov     ax, DR_SET SHL 8 + GRAF_DATA_ROT
                   1288:         out     dx, ax
                   1289: 
                   1290:         mov     ax, M_PROC_WRITE SHL 8 + GRAF_MODE
                   1291:         out     dx, ax
                   1292: 
                   1293:         mov     ax, 0FF00h + GRAF_BIT_MASK
                   1294:         out     dx, ax
                   1295: 
                   1296:         mov     ax, GRAF_ENAB_SR
                   1297:         out     dx, ax
                   1298: 
                   1299:         mov     dl, SEQ_ADDR
                   1300:         mov     ax, MM_ALL SHL 8 + SEQ_MAP_MASK
                   1301:         out     dx, ax
                   1302: 
                   1303:         call    clip_rects
                   1304: 
                   1305:         mov     eax,flPointer           ;lousy hack
                   1306:         or      eax,eax
                   1307:         jnz     draw_color_pointer      ;Color pointer?
                   1308: 
                   1309: ;-----------------------------------------------------------------------;
                   1310: ;                       Draw B/W Pointer
                   1311: ;-----------------------------------------------------------------------;
                   1312: 
                   1313: ;-----------------------------------------------------------------------;
                   1314: ; AND from the save area and the screen into the work area
                   1315: ;-----------------------------------------------------------------------;
                   1316: 
                   1317:         mov     al, fbAndRead
                   1318:         or      al, al
                   1319:         jz      done_and_portion
                   1320:         call    and_into_work
                   1321: done_and_portion:
                   1322: 
                   1323: ;-----------------------------------------------------------------------;
                   1324: ; Copy from save area to the screen and from the screen to the save
                   1325: ; area.
                   1326: ;-----------------------------------------------------------------------;
                   1327: 
                   1328:         mov     ax, WORD PTR fbFlush    ;Assume nothing to copy to/from save
                   1329: 
                   1330:         .ERRNZ  fbAndRead-fbFlush-1
                   1331: 
                   1332:         or      ah, al
                   1333:         jz      copied_things_around
                   1334:         call    copy_things_around
                   1335: copied_things_around:
                   1336: 
                   1337: 
                   1338: ;-----------------------------------------------------------------------;
                   1339: ; XOR from the work area to the screen
                   1340: ;-----------------------------------------------------------------------;
                   1341: 
                   1342:         mov     al, fbXor
                   1343:         or      al, al
                   1344:         jz      pointer_drawn
                   1345:         call    xor_to_screen
                   1346:         jmp     pointer_drawn
                   1347: 
                   1348: ;-----------------------------------------------------------------------;
                   1349: ;                       Draw Color Pointer
                   1350: ;-----------------------------------------------------------------------;
                   1351: 
                   1352: draw_color_pointer:
                   1353: 
                   1354: ;-----------------------------------------------------------------------;
                   1355: ; Copy from save area to the screen and from the screen to the save area.
                   1356: ;-----------------------------------------------------------------------;
                   1357: 
                   1358:         mov     ax, WORD PTR fbFlush    ;Assume nothing to copy to/from save
                   1359: 
                   1360:         .ERRNZ  fbAndRead-fbFlush-1
                   1361: 
                   1362:         or      ah, al
                   1363:         jz      things_copied_around
                   1364:         call    copy_things_around
                   1365: things_copied_around:
                   1366: 
                   1367: ;-----------------------------------------------------------------------;
                   1368: ; Draw color pointer to screen
                   1369: ;-----------------------------------------------------------------------;
                   1370: 
                   1371:         test    fbXor, 0FFh
                   1372:         jz      pointer_drawn
                   1373:         call    color_pointer_to_screen ;Planes must all be enabled
                   1374: 
                   1375: pointer_drawn:
                   1376:         mov     eax, ppdNew
                   1377:         xchg    eax, ppdOld
                   1378:         mov     ppdNew, eax
                   1379: draw_pointer_exit:
                   1380: 
                   1381: ;-----------------------------------------------------------------------;
                   1382: ; Reset WRITE mode of EGA/VGA to WRITE MODE 0, READ MODE 1
                   1383: ;-----------------------------------------------------------------------;
                   1384: 
                   1385:         mov     al, MM_ALL              ;Set Map Mask for all write
                   1386:         mov     dx, EGA_BASE + SEQ_DATA
                   1387:         out     dx, al
                   1388: 
                   1389:         mov     dx, EGA_BASE + GRAF_ADDR
                   1390:         mov     ax, DR_SET SHL 8 + GRAF_DATA_ROT
                   1391:         out     dx, ax
                   1392: 
                   1393:         mov     ax, M_PROC_WRITE SHL 8 + GRAF_MODE
                   1394:         out     dx, ax
                   1395: 
                   1396:         mov     ax, 0FF00h + GRAF_BIT_MASK
                   1397:         out     dx, ax
                   1398: 
                   1399:         mov     ax, GRAF_ENAB_SR
                   1400:         out     dx, ax
                   1401: 
                   1402:         cRet    vDrawPointer
                   1403: 
                   1404: ;-----------------------------------------------------------------------;
                   1405: ; The following routines would be procs, outside the scope of
                   1406: ; vDrawPointer, but then they couldn't access vDrawPointer's stack
                   1407: ; frame, which they need to.
                   1408: ;-----------------------------------------------------------------------;
                   1409: 
                   1410: page
                   1411: 
                   1412: ;--------------------------Private-Routine------------------------------;
                   1413: ; compute_rects
                   1414: ;
                   1415: ; This routine computes the rectangles which describe what needs to be
                   1416: ; read/ANDed/XORed/written.  The rectangles are unclipped.  Clipping
                   1417: ; must be performed by a different routine.
                   1418: ;
                   1419: ; Entry:
                   1420: ;       AX  =  0
                   1421: ;       SI --> currently displayed pointer's rectangle data
                   1422: ;       DI --> new pointer's rectangle data
                   1423: ; Returns:
                   1424: ;       None
                   1425: ; Error Returns:
                   1426: ;       None
                   1427: ; Registers Preserved:
                   1428: ;       BP
                   1429: ; Registers Destroyed:
                   1430: ;       AX,BX,CX,DX,SI,DI,FLAGS
                   1431: ; Calls:
                   1432: ;       None
                   1433: ;
                   1434: ;-----------------------------------------------------------------------;
                   1435: 
                   1436:         align   4
                   1437: compute_rects:
                   1438: 
                   1439:         push    ebp
                   1440: 
                   1441:         mov     WORD PTR fbFlush, ax    ;Assume nothing to restore to screen
                   1442: 
                   1443:         .ERRNZ  fbAndRead-fbFlush-1     ;Assume nothing to read/And to work
                   1444: 
                   1445:         mov     fbXor, FB_NEW_PTR       ;Assume new pointer is XORed to screen
                   1446:         test    [esi].pd_fb, PD_VALID
                   1447:         jz      old_pointer_is_invalid
                   1448: 
                   1449: ;-----------------------------------------------------------------------;
                   1450: ; There is a pointer currently displayed on the screen.  If the new
                   1451: ; pointer is far enough away from the old pointer, then we won't have
                   1452: ; to deal with overlap.
                   1453: ;-----------------------------------------------------------------------;
                   1454: 
                   1455: old_pointer_is_valid:
                   1456:         mov     eax, [edi].pd_rd.rd_ptlScreen.ptl_x
                   1457:         sub     eax, [esi].pd_rd.rd_ptlScreen.ptl_x
                   1458:         mov     bl, al                  ;BL = delta x
                   1459:         or      eax, eax                ;EAX = |EAX|
                   1460:         jns     @F
                   1461:         neg     eax
                   1462: @@:
                   1463:         cmp     eax, sizlMaxDelta.sizl_cx
                   1464:         jae     rects_are_disjoint
                   1465:         mov     eax, [edi].pd_rd.rd_ptlScreen.ptl_y
                   1466:         sub     eax, [esi].pd_rd.rd_ptlScreen.ptl_y
                   1467:         mov     bh, al                  ;BH = delta y
                   1468:         or      eax, eax                ;EAX = |EAX|
                   1469:         jns     @F
                   1470:         neg     eax
                   1471: @@:
                   1472:         cmp     eax, sizlMaxDelta.sizl_cy
                   1473:         jb      rects_overlap           ;(or are identical)
                   1474: 
                   1475: ;-----------------------------------------------------------------------;
                   1476: ; The rectangles will be disjoint.  Set up to restore under the old
                   1477: ; pointer, copy the new rectangle to the save area, and AND it into
                   1478: ; the work area.
                   1479: ;-----------------------------------------------------------------------;
                   1480: 
                   1481: rects_are_disjoint:
                   1482:         mov     fbFlush, FB_OLD_PTR
                   1483: 
                   1484: ;-----------------------------------------------------------------------;
                   1485: ; The save area image is invalid, so we won't have to copy it to the
                   1486: ; screen or AND some part of it into the work area.  We'll simply want
                   1487: ; to copy the new area to the save area and AND it into the work area.
                   1488: ; This can be treated the same as if the rectangles are identical,
                   1489: ; except we want to reset the origin within the save buffer.
                   1490: ;-----------------------------------------------------------------------;
                   1491: 
                   1492: old_pointer_is_invalid:
                   1493:         mov     ax, ptbInitOrigin       ;Reset origin within the save area
                   1494:         mov     [edi].pd_rd.rd_ptbSave,ax
                   1495: 
                   1496:         .ERRNZ  (SIZE POINTB) - 2
                   1497: 
                   1498:         mov     fbAndRead, FB_NEW_PTR   ;Copy new ptr to save and XOR to work
                   1499:         jmp     compute_rects_exit
                   1500: 
                   1501: 
                   1502: ;-----------------------------------------------------------------------;
                   1503: ; The rectangles overlap in some manner.  Compute how the rectangles,
                   1504: ; will overlap, setting up the various needed rectangle structures as
                   1505: ; we go.
                   1506: ;
                   1507: ; The only hope we have of computing the overlap rectangle is to
                   1508: ; initialize it to some known state and adjusting it as we process
                   1509: ; dx and dy.  We will initialize it to be the upper left hand corner
                   1510: ; of the old pointer rectangle.
                   1511: ;
                   1512: ; Currently:
                   1513: ;       AX     =  old pointer's pd_rd.rd_ptbSave
                   1514: ;       BH     =  dy
                   1515: ;       BL     =  dx (negative)
                   1516: ;       SI     --> old pointer's rd_ptlScreen
                   1517: ;       DI     --> new pointer rectangle
                   1518: ;-----------------------------------------------------------------------;
                   1519: 
                   1520: rects_overlap:
                   1521: 
                   1522: ; Set old pointer's save buffer (X,Y) into the overlap rectangle.
                   1523: ; Also set this as the save buffer origin for the new pointer rectangle.
                   1524: 
                   1525:         lodsw
                   1526: 
                   1527:         .ERRNZ  pd_rd.rd_ptbSave
                   1528: 
                   1529:         mov     rdOverlap.rd_ptbSave, ax
                   1530:         mov     [edi].pd_rd.rd_ptbSave, ax
                   1531:         mov     dx, ax
                   1532: 
                   1533: ; Set old pointer's screen (X,Y) into the overlap rectangle as the
                   1534: ; screen origin.
                   1535: 
                   1536:         lodsd
                   1537: 
                   1538:         .ERRNZ  rd_ptlScreen-rd_ptbSave-2
                   1539:         .ERRNZ  ptl_x
                   1540: 
                   1541:         mov     rdOverlap.rd_ptlScreen.ptl_x, eax
                   1542:         mov     ebp, eax
                   1543:         lodsd
                   1544: 
                   1545:         .ERRNZ  ptl_y-ptl_x-4
                   1546: 
                   1547:         mov     rdOverlap.rd_ptlScreen.ptl_y, eax
                   1548:         mov     esi, eax
                   1549: 
                   1550: ; Set the mask width and height into the overlap rectangle
                   1551: 
                   1552:         mov     ax, sizbMask
                   1553:         mov     rdOverlap.rd_sizb, ax
                   1554: 
                   1555:         .ERRNZ  sizb_cy-sizb_cx-1
                   1556:         .ERRNZ  (SIZE SIZEB) - 2
                   1557: 
                   1558:         mov     ecx, eax
                   1559: 
                   1560:         .ERRNZ  sizb_cy-sizb_cx-1
                   1561: 
                   1562: ; Set the work buffer origin to be zero
                   1563: 
                   1564:         xor     eax, eax
                   1565:         mov     rdOverlap.rd_ptbWork, ax
                   1566: 
                   1567: ; Show that the overlap rectangle exists and should be ANDed into the
                   1568: ; work area, then dispatch based on dx,dy.
                   1569: 
                   1570:         mov     fbAndRead, FB_OVERLAP
                   1571:         or      bl, bl                  ; Dispatch based on dx
                   1572:         jg      moved_right
                   1573:         jl      moved_left
                   1574:         jmp     processed_x_overlap
                   1575: 
                   1576: 
                   1577: ;-----------------------------------------------------------------------;
                   1578: ; The starting X of the new rectangle is to be set as the new lhs.
                   1579: ;
                   1580: ;      * nnnnn $ onononono oooooooo     * = start of new rectangle
                   1581: ;                         o       o     $ = start of old rectangle
                   1582: ;      n   |   o    |     n   |   o
                   1583: ;      n   |   n          o   |   o
                   1584: ;      n   |   o    O     n       o
                   1585: ;      n       n    v     o   F   o
                   1586: ;      n   R   o    e     n   l   o
                   1587: ;      n   e   n    r     o   u   o
                   1588: ;      n   a   o    l     n   s   o
                   1589: ;      n   d   n    a     o   h   o
                   1590: ;      n       o    p     n       o
                   1591: ;      n   |   n          o   |   o
                   1592: ;      n   |   o    |     n   |   o
                   1593: ;      n   |   n    |     o   |   o
                   1594: ;      n       o          n       o
                   1595: ;      nnnnnnnn nonononono oooooooo
                   1596: ;
                   1597: ;      |-- dx -|          |-- dx -|
                   1598: ;      |-sizbMask.sizb_cx-|
                   1599: ;
                   1600: ;
                   1601: ; Currently:
                   1602: ;       AX =    0
                   1603: ;       BH =    dy
                   1604: ;       BL =    dx (negative)
                   1605: ;       CH =    buffer height
                   1606: ;       CL =    buffer width
                   1607: ;       DH =    old pointer's Y coordinate in save area
                   1608: ;       DL =    old pointer's X coordinate in save area
                   1609: ;       SI =    old pointer's Y screen coordinate
                   1610: ;       BP =    old pointer's X screen coordinate
                   1611: ;       DI =    --> new pointer's RECT_DATA
                   1612: ;-----------------------------------------------------------------------;
                   1613: 
                   1614: moved_left:
                   1615: 
                   1616: ; The Read buffer will map into the work area at (0,0).
                   1617: 
                   1618:         mov     rdReadX.rd_ptbWork, ax
                   1619: 
                   1620: ; The width of the overlap area is sizbMask.sizb_cx - |dx|.
                   1621: 
                   1622:         mov     al, bl                  ;BL = dx (which is negative)
                   1623:         add     al, cl                  ;CL = sizbMask.sizb_cx
                   1624:         mov     rdOverlap.rd_sizb.sizb_cx, al
                   1625: 
                   1626: ; The flush rectangle's X is ptlScreen.ptl_x + sizbMask.sizb_cx - |dx|.
                   1627: 
                   1628:         add     eax, ebp                ;AX = sizbMask.sizb_cx - |dx|
                   1629:         mov     rdFlushX.rd_ptlScreen.ptl_x, eax
                   1630: 
                   1631: ; Compute where in the save buffer the new lhs will map to.  We must
                   1632: ; update the new pointer's rectangle to reflect where this origin is.
                   1633: 
                   1634:         mov     eax, edx                ;DX = old ptbSave
                   1635:         add     al, bl                  ;BL = dx (negative)
                   1636:         add     ah, bh                  ;BH = dy
                   1637:         and     eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
                   1638:         mov     [edi].pd_rd.rd_ptbSave.ptb_x, al
                   1639:         mov     rdReadX.rd_ptbSave, ax
                   1640: 
                   1641:         .ERRNZ  ptb_y-ptb_x-1
                   1642: 
                   1643: ; The origin of the flush rectangle is sizbMask.sizb_cx bytes away
                   1644: ; from the origin of the read rectangle.
                   1645: 
                   1646:         add     al, cl
                   1647:         and     al, SAVE_BUFFER_WIDTH-1 ;Handle any wrap
                   1648:         mov     ah, dh
                   1649:         mov     rdFlushX.rd_ptbSave, ax
                   1650: 
                   1651: ; Compute |dx|.  This is the width of the read and flush rectangles.
                   1652: ; The height will be set to the working height.  |dx| is also the
                   1653: ; overlap rectangle's work area X coordinate.
                   1654: 
                   1655:         mov     al, bl                  ;BL = dx (negative)
                   1656:         neg     al                      ;AL = |dx|
                   1657:         mov     ah, ch                  ;CH = sizbMask.sizb_cy
                   1658:         mov     rdFlushX.rd_sizb, ax
                   1659:         mov     rdReadX.rd_sizb, ax
                   1660: 
                   1661:         .ERRNZ  sizb_cy-sizb_cx-1
                   1662: 
                   1663:         mov     rdOverlap.rd_ptbWork.ptb_x, al
                   1664: 
                   1665: ; The Read buffer's screen address is the ptlScreen stored in the new
                   1666: ; pointer's RECT_DATA.
                   1667: 
                   1668:         mov     eax, [edi].pd_rd.rd_ptlScreen.ptl_x
                   1669:         jmp     finish_x_overlap
                   1670: 
                   1671: 
                   1672: 
                   1673: ;-----------------------------------------------------------------------;
                   1674: ; The starting X of the new rectangle is somewhere in the middle
                   1675: ; of the old rectangle.
                   1676: ;
                   1677: ;      $ ooooo * onononono nnnnnnn     * = start of new rectangle
                   1678: ;      o       n          o      n     $ = start of old rectangle
                   1679: ;      o   |   o    |     n   |  n
                   1680: ;      o   |   n          o   |  n
                   1681: ;      o       o    O     n   |  n
                   1682: ;      o   F   n    v     o      n
                   1683: ;      o   l   o    e     n   R  n
                   1684: ;      o   u   n    r     o   e  n
                   1685: ;      o   s   o    l     n   a  n
                   1686: ;      o   h   n    a     o   d  n
                   1687: ;      o       o    p     n      n
                   1688: ;      o   |   n          o   |  n
                   1689: ;      o   |   o    |     n   |  n
                   1690: ;      o   |   n    |     o   |  n
                   1691: ;      o       o          n      n
                   1692: ;      oooooooo nonononono nnnnnnn
                   1693: ;
                   1694: ;      |-- dx -|          |-- dx -|
                   1695: ;      |-sizbMask.sizb_cx-|
                   1696: ;
                   1697: ;
                   1698: ; Currently:
                   1699: ;       AX =    0
                   1700: ;       BH =    dy
                   1701: ;       BL =    dx (positive)
                   1702: ;       CH =    buffer height
                   1703: ;       CL =    buffer width
                   1704: ;       DH =    old pointer's Y coordinate in save area
                   1705: ;       DL =    old pointer's X coordinate in save area
                   1706: ;       SI =    old pointer's Y screen coordinate
                   1707: ;       BP =    old pointer's X screen coordinate
                   1708: ;       DI =    --> new pointer's RECT_DATA
                   1709: ;-----------------------------------------------------------------------;
                   1710: 
                   1711: moved_right:
                   1712: 
                   1713: ; The screen X origin of the overlap rectangle is the new rectangle's
                   1714: ; X coordinate, or the old rectangle's X coordinate + |dx|.
                   1715: 
                   1716:         mov     al, bl
                   1717:         add     rdOverlap.rd_ptlScreen.ptl_x, eax
                   1718: 
                   1719: ; The width of the read and flush buffers is |dx|.  The height is
                   1720: ; just the working height.
                   1721: 
                   1722:         mov     ah, ch                  ;CH = sizbMask.sizb_cy
                   1723:         mov     rdFlushX.rd_sizb, ax
                   1724:         mov     rdReadX.rd_sizb, ax
                   1725: 
                   1726:         .ERRNZ  sizb_cy-sizb_cx-1
                   1727: 
                   1728: ; Compute where the new lhs is in the save area.  This will be the lhs
                   1729: ; of both the new rectangle and the overlap area.
                   1730: 
                   1731:         add     al, dl                  ;DL = ptbSave.ptb_x
                   1732:         and     al, SAVE_BUFFER_WIDTH-1 ;Handle any wrap
                   1733:         mov     [edi].pd_rd.rd_ptbSave.ptb_x, al
                   1734:         mov     rdOverlap.rd_ptbSave.ptb_x, al
                   1735: 
                   1736: ; The data to be flushed will come from the lhs of the old rectangle
                   1737: 
                   1738:         mov     eax, edx
                   1739:         mov     rdFlushX.rd_ptbSave, ax
                   1740: 
                   1741: ; The data to be read will go at the old lhs + sizbMask.sizb_cx.  The
                   1742: ; Y component will be the new Y.
                   1743: 
                   1744:         add     al, cl
                   1745:         add     ah, bh
                   1746:         and     eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
                   1747:         mov     rdReadX.rd_ptbSave, ax
                   1748: 
                   1749:         .ERRNZ  ptb_y-ptb_x-1
                   1750: 
                   1751: ; The X screen origin of the flush buffer is the old ptlScreen.ptl_x
                   1752: 
                   1753:         mov     rdFlushX.rd_ptlScreen.ptl_x, ebp
                   1754: 
                   1755: ; The width of the overlap rectangle is sizbMask.sizb_cx - |dx|.  This
                   1756: ; is also the X offset into the work area of the read rectangle.
                   1757: ; The Y offset is zero.
                   1758: 
                   1759:         mov     al, cl
                   1760:         sub     al, bl
                   1761:         mov     rdOverlap.rd_sizb.sizb_cx, al
                   1762:         movsx   eax, al
                   1763:         mov     rdReadX.rd_ptbWork, ax
                   1764: 
                   1765:         .ERRNZ  ptb_y-ptb_x-1
                   1766: 
                   1767: ; The screen Y origin of the read rectangle is the new rectangle's Y
                   1768: ; coordinate.  The X coordinate can be computed as the old rectangles
                   1769: ; X coordinate + the save width
                   1770: 
                   1771:         mov     al, cl
                   1772:         add     eax, ebp
                   1773: 
                   1774: finish_x_overlap:
                   1775:         mov     rdReadX.rd_ptlScreen.ptl_x, eax
                   1776:         mov     eax, [edi].pd_rd.rd_ptlScreen.ptl_y
                   1777:         mov     rdReadX.rd_ptlScreen.ptl_y, eax
                   1778: 
                   1779: ; The Y address of the flush rectangle on the screen is ptlScreen.ptl_y.
                   1780: 
                   1781:         mov     rdFlushX.rd_ptlScreen.ptl_y, esi
                   1782: 
                   1783: ; Set the flags to show that there is some form of X overlap.  We want
                   1784: ; to show that there is some X rectangle to be read/flushed, and that
                   1785: ; there is some overlap rectangle to be processed.
                   1786: 
                   1787:         or      WORD PTR fbFlush, (FB_READ_X SHL 8) + FB_FLUSH_X
                   1788: 
                   1789:         .ERRNZ  fbAndRead-fbFlush-1
                   1790: 
                   1791:         xor     eax, eax
                   1792: 
                   1793: processed_x_overlap:
                   1794:         or      bh, bh
                   1795:         jg      moved_down
                   1796:         jz      processed_y_overlap_relay
                   1797: 
                   1798: 
                   1799: ;-----------------------------------------------------------------------;
                   1800: ; The starting Y of the new rectangle is to be set as the new top.
                   1801: ;
                   1802: ;   * = start of new rectangle
                   1803: ;   $ = start of old rectangle
                   1804: ;
                   1805: ;      $ oooooooooooooooooooooooooo   ---  ---
                   1806: ;      o                          o    |    |
                   1807: ;      o -------- Read ---------- o    dy   |
                   1808: ;                                 o    |    |
                   1809: ;      * onononononononononononono    ---
                   1810: ;                                 n       sizbMask.sizb_cy - dy
                   1811: ;      n                          o
                   1812: ;      o ------- Overlap -------- n         |
                   1813: ;      n                          o         |
                   1814: ;      o                          n         |
                   1815: ;       ononononononononononononon    ---  ---
                   1816: ;      n                          n    |
                   1817: ;      n -------- Write --------- n    dy
                   1818: ;      n                          n    |
                   1819: ;      nnnnnnnnnnnnnnnnnnnnnnnnnnnn   ---
                   1820: ;
                   1821: ;
                   1822: ;
                   1823: ; Currently:
                   1824: ;       AX =    0
                   1825: ;       BH =    dy (negative)
                   1826: ;       BL =    dx
                   1827: ;       CH =    buffer height
                   1828: ;       CL =    buffer width
                   1829: ;       DH =    old pointer's Y coordinate in save area
                   1830: ;       DL =    old pointer's X coordinate in save area
                   1831: ;       SI =    old pointer's Y screen coordinate
                   1832: ;       BP =    old pointer's X screen coordinate
                   1833: ;       DI =    --> new pointer's RECT_DATA
                   1834: ;-----------------------------------------------------------------------;
                   1835: 
                   1836: moved_up:
                   1837: 
                   1838: ; The Read buffer will map into the work area at (0,0).
                   1839: 
                   1840:         mov     rdReadY.rd_ptbWork, ax
                   1841: 
                   1842: ; The height of the overlap area is sizbMask.sizb_cy - |dy|.
                   1843: 
                   1844:         mov     al, bh                  ;BH = dy (which is negative)
                   1845:         add     al, ch                  ;CH = sizbMask.sizb_cy
                   1846:         mov     rdOverlap.rd_sizb.sizb_cy, al
                   1847: 
                   1848: ; The flush rectangle's Y is ptlScreen.ptl_y + sizbMask.sizb_cy - |dy|.
                   1849: 
                   1850:         add     eax, esi                ;EAX = sizbMask.sizb_cy - |dy|
                   1851:         mov     rdFlushY.rd_ptlScreen.ptl_y, eax
                   1852: 
                   1853: ; Compute where in the save buffer the new top will map to.  We must
                   1854: ; update the new pointer's rectangle to reflect where this origin is.
                   1855: 
                   1856:         mov     eax, edx                ;DX = old ptbSave
                   1857:         add     ah, bh                  ;BH = dy (negative)
                   1858:         add     al, bl
                   1859:         and     eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
                   1860:         mov     [edi].pd_rd.rd_ptbSave.ptb_y, ah
                   1861:         mov     rdReadY.rd_ptbSave, ax
                   1862: 
                   1863:         .ERRNZ  ptb_y-ptb_x-1
                   1864: 
                   1865: ; The origin of the flush rectangle is sizbMask.sizb_cy scans away
                   1866: ; from the origin of the read rectangle.
                   1867: 
                   1868:         add     ah, ch
                   1869:         and     ah, SAVE_BUFFER_HEIGHT-1 ;Handle any wrap
                   1870:         mov     al, dl
                   1871:         mov     rdFlushY.rd_ptbSave, ax
                   1872: 
                   1873: ; Compute |dy|.  This is the height of the read and flush rectangles.
                   1874: ; The width will be set to the working width.  |dy| is also the
                   1875: ; overlap rectangle's work area Y coordinate.
                   1876: 
                   1877:         mov     ah, bh                  ;BH = dy
                   1878:         neg     ah                      ;Make it |dy|
                   1879:         mov     al, cl                  ;CL = sizbMask.sizb_cx
                   1880:         mov     rdFlushY.rd_sizb, ax
                   1881:         mov     rdReadY.rd_sizb, ax
                   1882: 
                   1883:         .ERRNZ  sizb_cy-sizb_cx-1
                   1884: 
                   1885:         mov     rdOverlap.rd_ptbWork.ptb_y, ah
                   1886: 
                   1887: ; The Read buffer's screen address is the ptlScreen stored in the new
                   1888: ; pointer's RECT_DATA.
                   1889: 
                   1890:         mov     eax, [edi].pd_rd.rd_ptlScreen.ptl_y
                   1891:         jmp     finish_y_overlap
                   1892: 
                   1893: processed_y_overlap_relay:
                   1894:         jmp     processed_y_overlap
                   1895: 
                   1896: 
                   1897: 
                   1898: ;-----------------------------------------------------------------------;
                   1899: ; The starting Y of the new rectangle is somewhere in the middle
                   1900: ; of the old rectangle.
                   1901: ;
                   1902: ;   * = start of new rectangle
                   1903: ;   $ = start of old rectangle
                   1904: ;
                   1905: ;      $ oooooooooooooooooooooooooo   ---  ---
                   1906: ;      o                          o    |    |
                   1907: ;      o -------- Write --------- o    dy   |
                   1908: ;                                 o    |    |
                   1909: ;      * onononononononononononono    ---
                   1910: ;                                 n       sizbMask.sizb_cy - dy
                   1911: ;      n                          o
                   1912: ;      o ------- Overlap -------- n         |
                   1913: ;      n                          o         |
                   1914: ;      o                          n         |
                   1915: ;       ononononononononononononon    ---  ---
                   1916: ;      n                          n    |
                   1917: ;      n -------- Read ---------- n    dy
                   1918: ;      n                          n    |
                   1919: ;      nnnnnnnnnnnnnnnnnnnnnnnnnnnn   ---
                   1920: ;
                   1921: ;
                   1922: ; Currently:
                   1923: ;       AX =    0
                   1924: ;       BH =    dy (positive)
                   1925: ;       BL =    dx
                   1926: ;       CH =    buffer height
                   1927: ;       CL =    buffer width
                   1928: ;       DH =    old pointer's Y coordinate in save area
                   1929: ;       DL =    old pointer's X coordinate in save area
                   1930: ;       SI =    old pointer's Y screen coordinate
                   1931: ;       BP =    old pointer's X screen coordinate
                   1932: ;       DI =    --> new pointer's RECT_DATA
                   1933: ;-----------------------------------------------------------------------;
                   1934: 
                   1935: moved_down:
                   1936: 
                   1937: ; The screen Y origin of the overlap rectangle is the new rectangle's
                   1938: ; Y coordinate, or the old rectangle's Y coordinate + |dy|.
                   1939: 
                   1940:         mov     al, bh
                   1941:         add     rdOverlap.rd_ptlScreen.ptl_y, eax
                   1942: 
                   1943: ; Compute where the new top is.  This will be both the top of the new
                   1944: ; rectangle and the overlap area.
                   1945: 
                   1946: ;       mov     al, bh                  ;BH = |dy|
                   1947:         add     al, dh                  ;DH = ptbSave.ptb_y
                   1948:         and     al, SAVE_BUFFER_HEIGHT-1 ;CH = sizbMask.sizb_cy
                   1949:         mov     [edi].pd_rd.rd_ptbSave.ptb_y, al
                   1950:         mov     rdOverlap.rd_ptbSave.ptb_y, al
                   1951: 
                   1952: ; The height of the read and flush buffers is |dy|.  The width is
                   1953: ; just the working width.
                   1954: 
                   1955:         mov     ah, bh
                   1956:         mov     al, cl                  ;CL = sizbMask.sizb_cx
                   1957:         mov     rdFlushY.rd_sizb, ax
                   1958:         mov     rdReadY.rd_sizb, ax
                   1959: 
                   1960:         .ERRNZ  sizb_cy-sizb_cx-1
                   1961: 
                   1962: ; The data to be flushed will come from the top of the old rectangle
                   1963: 
                   1964:         mov     eax, edx
                   1965:         mov     rdFlushY.rd_ptbSave, dx
                   1966: 
                   1967: ; The data to be read will go at the old top + sizbMask.sizb_cy
                   1968: 
                   1969:         add     ah, ch
                   1970:         add     al, bl
                   1971:         and     eax, ((SAVE_BUFFER_HEIGHT-1) SHL 8) + SAVE_BUFFER_WIDTH-1
                   1972:         mov     rdReadY.rd_ptbSave, ax
                   1973: 
                   1974:         .ERRNZ  ptb_y-ptb_x-1
                   1975: 
                   1976: ; The Y screen origin of the flush buffer is the old ptlScreen.ptl_y
                   1977: 
                   1978:         mov     rdFlushY.rd_ptlScreen.ptl_y, esi
                   1979: 
                   1980: ; The height of the overlap rectangle is sizbMask.sizb_cy - |dy|.
                   1981: ; This is also the Y offset into the work area of the read rectangle.
                   1982: ; The X offset is zero.
                   1983: 
                   1984:         mov     ah, ch
                   1985:         sub     ah, bh
                   1986:         mov     rdOverlap.rd_sizb.sizb_cy, ah
                   1987:         xor     al, al
                   1988:         mov     rdReadY.rd_ptbWork, ax
                   1989: 
                   1990:         .ERRNZ  ptb_y-ptb_x-1
                   1991: 
                   1992: ; The screen X origin of the read rectangle is the new rectangle's X
                   1993: ; coordinate.  The Y coordinate can be computed as the old
                   1994: ; rectangle's Y coordinate + the save height
                   1995: 
                   1996:         mov     al, ch
                   1997:         xor     ah, ah
                   1998:         add     eax, esi
                   1999: 
                   2000: finish_y_overlap:
                   2001:         mov     rdReadY.rd_ptlScreen.ptl_y, eax
                   2002:         mov     eax, [edi].pd_rd.rd_ptlScreen.ptl_x
                   2003:         mov     rdReadY.rd_ptlScreen.ptl_x, eax
                   2004: 
                   2005: ; The X address of the flush rectangle on the screen is ptlScreen.ptl_x.
                   2006: 
                   2007:         mov     rdFlushY.rd_ptlScreen.ptl_x, ebp
                   2008: 
                   2009: ; Set the flags to show that there is some form of Y overlap.  We want
                   2010: ; to show that there is some Y rectangle to be read/flushed, and that
                   2011: ; there is some overlap rectangle to be processed.
                   2012: 
                   2013:         or      WORD PTR fbFlush, ((FB_READ_Y OR FB_OVERLAP) SHL 8) + FB_FLUSH_Y
                   2014: 
                   2015:         .ERRNZ  fbAndRead-fbFlush-1
                   2016: 
                   2017: 
                   2018: ;-----------------------------------------------------------------------;
                   2019: ; We have computed the seperate X and Y componets of the overlap.  If
                   2020: ; there was both dx and dy, then we have an L shaped area which we'll
                   2021: ; be reading/writing.  In this case, we want to remove the overlapping
                   2022: ; portion of the L.
                   2023: ;-----------------------------------------------------------------------;
                   2024: 
                   2025:         or      bl, bl
                   2026:         jz      processed_y_overlap
                   2027: 
                   2028: ;-----------------------------------------------------------------------;
                   2029: ; We have something which looks like one of the following:
                   2030: ;
                   2031: ;   ----------               ----------
                   2032: ;  |  flush   |             |  flush   |    dy > 0
                   2033: ;  | f        |             |        f |
                   2034: ;  | l  ----------       ----------  l |    -----
                   2035: ;  | u |      |   |     |   |      | u |      |
                   2036: ;  | s |      |   |     |   |      | s |    limit the "x" rectangles to
                   2037: ;  | h |  1   | r |     | r |   2  | h |    this height
                   2038: ;  |   |      | e |     | e |      |   |      |
                   2039: ;   ---|------  a |     | a  ------|---     -----
                   2040: ;      |        d |     | d        |  \
                   2041: ;      |   read   |     |   read   |\  \
                   2042: ;       ----------       ----------  \  \
                   2043: ;                                     \  \_____ The "x" overlap rectangle
                   2044: ;                                      \
                   2045: ;                                       \______ The "y" overlap rectangle
                   2046: ;
                   2047: ;
                   2048: ;
                   2049: ;   ----------               ----------     dy < 0
                   2050: ;  |   read   |             |   read   |
                   2051: ;  | r        |             |        r |
                   2052: ;  | e  ------|---       ---|------  e |    -----
                   2053: ;  | a |      |   |     |   |      | a |      |
                   2054: ;  | d |      | f |     | f |      | d |    limit the "x" rectangles to
                   2055: ;  |   |  3   | l |     | l |   4  |   |    this height
                   2056: ;  |   |      | u |     | u |      |   |      |
                   2057: ;   ----------  s |     | s  ----------     -----
                   2058: ;      |        h |     | h        |
                   2059: ;      |  flush   |     |   flush  |
                   2060: ;       ----------       ----------
                   2061: ;
                   2062: ;
                   2063: ; The corners of the L shape are contained in both the X and Y
                   2064: ; rectangles we just created.  We'll remove the overlap from the
                   2065: ; X rectangles.  To do this, we must subtract |dy| from the height
                   2066: ; stored in the rectangles (which is sizbMask.sizb_cy) and adjust
                   2067: ; X parameters of either the read or flush rectangles.
                   2068: ;
                   2069: ; For cases 1 and 2, we want to adjust X parameters of the flush
                   2070: ; rectangle.  For cases 3 and 4, we want to adjust X parameters
                   2071: ; of the read rectangle.
                   2072: ;
                   2073: ; Currently:
                   2074: ;       BH =    dy
                   2075: ;       BL =    dx
                   2076: ;       CH =    buffer height
                   2077: ;       CL =    buffer width
                   2078: ;       DH =    old pointer's Y coordinate in save area
                   2079: ;       DL =    old pointer's X coordinate in save area
                   2080: ;       SI =    old pointer's Y screen coordinate
                   2081: ;       BP =    old pointer's X screen coordinate
                   2082: ;       DI =    --> new pointer's RECT_DATA
                   2083: ;-----------------------------------------------------------------------;
                   2084: 
                   2085:         mov     al, bh
                   2086:         mov     ebx, offset FLAT:rdFlushX  ;Assume cases 1 and 2
                   2087:         or      al, al
                   2088:         jns     @F
                   2089:         mov     ebx, offset FLAT:rdReadX   ;Its cases 3 and 4
                   2090:         neg     al                      ;|dy|
                   2091:         add     [ebx].rd_ptbWork.ptb_y, al;Move down in the work area too!
                   2092: @@:
                   2093:         mov     cl, [ebx].rd_ptbSave.ptb_y
                   2094:         add     cl, al
                   2095:         and     cl, SAVE_BUFFER_HEIGHT-1
                   2096:         mov     [ebx].rd_ptbSave.ptb_y, cl
                   2097:         movsx   eax, al
                   2098: 
                   2099:         .ERRNZ  (SAVE_BUFFER_HEIGHT-1) AND 80h
                   2100: 
                   2101:         add     [ebx].rd_ptlScreen.ptl_y, eax
                   2102:         neg     al
                   2103:         add     al, ch                  ;sizbMask.sizb_cy - |dy|
                   2104:         mov     rdFlushX.rd_sizb.sizb_cy, al
                   2105:         mov     rdReadX.rd_sizb.sizb_cy, al
                   2106: 
                   2107: processed_y_overlap:
                   2108: compute_rects_exit:
                   2109: 
                   2110:         pop     ebp
                   2111: 
                   2112:         PLAIN_RET
                   2113: 
                   2114: page
                   2115: 
                   2116: ;--------------------------Private-Routine------------------------------;
                   2117: ; clip_rects
                   2118: ;
                   2119: ; This routine clips the rectangles computed by compute_rects.
                   2120: ;
                   2121: ; Entry:
                   2122: ;       None
                   2123: ; Returns:
                   2124: ;       None
                   2125: ; Error Returns:
                   2126: ;       None
                   2127: ; Registers Preserved:
                   2128: ;       BP
                   2129: ; Registers Destroyed:
                   2130: ;       AX,BX,CX,DX,SI,DI,FLAGS
                   2131: ; Calls:
                   2132: ;       do_clipping
                   2133: ;
                   2134: ;-----------------------------------------------------------------------;
                   2135: 
                   2136:         align   4
                   2137: clip_rects:
                   2138: 
                   2139:         mov     esi, ppdOld             ;--> old POINTER_DATA structure
                   2140:         mov     dl, [esi].pd_fb
                   2141:         test    dl, PD_CLIPPED          ;Won't be set if PD_VALID isn't set
                   2142:         jz      old_been_clipped
                   2143: 
                   2144: ;-----------------------------------------------------------------------;
                   2145: ; The old pointer needs some form of clipping.  This can affect either
                   2146: ; the old pointer's rectangle or rdFlushX and rdFlushY.  Since the old
                   2147: ; pointer's rectangle will be discarded after it is restored, we don't
                   2148: ; care if we write over it's contents.
                   2149: ;-----------------------------------------------------------------------;
                   2150: 
                   2151:         mov     edi, esi                        ;EDI --> rectangle to clip
                   2152:         mov     bl, fbFlush             ;fbFlush tells us which rects to use
                   2153:         mov     bh, FB_OLD_PTR
                   2154:         test    bl, bh
                   2155:         jnz     call_do_clip            ;Only have to clip old pointer's rect
                   2156:         mov     edi, offset FLAT:rdFlushX
                   2157:         mov     bh, FB_FLUSH_X
                   2158:         test    bl, bh
                   2159:         jz      @F
                   2160:         call    do_clipping
                   2161: @@:
                   2162:         mov     edi, offset FLAT:rdFlushY
                   2163:         mov     bh, FB_FLUSH_Y
                   2164:         test    bl, bh
                   2165:         jz      @F
                   2166: call_do_clip:
                   2167:         call    do_clipping
                   2168: @@:
                   2169:         mov     fbFlush, bl
                   2170: 
                   2171:         mov     edi, offset FLAT:rdOverlap
                   2172:         mov     bl, fbAndRead
                   2173:         mov     bh, FB_OVERLAP
                   2174:         test    bl, bh
                   2175:         jz      @F
                   2176:         call    do_clipping
                   2177:         mov     fbAndRead, bl
                   2178: @@:
                   2179: old_been_clipped:
                   2180: 
                   2181: 
                   2182: ;-----------------------------------------------------------------------;
                   2183: ; The old pointer rectangle has been clipped.  Now see about clipping
                   2184: ; the new pointer rectangle.
                   2185: ;-----------------------------------------------------------------------;
                   2186: 
                   2187:         mov     esi, ppdNew             ;--> new POINTER_DATA structure
                   2188:         mov     dl, [esi].pd_fb
                   2189:         test    dl, PD_CLIPPED          ;Won't be set if PD_VALID isn't set
                   2190:         jz      new_been_clipped
                   2191: 
                   2192: ;-----------------------------------------------------------------------;
                   2193: ; The new rectangle structure needs to be clipped.  This presents a
                   2194: ; minor problem in that we don't want to destroy the screen X,Y and
                   2195: ; buffer X,Y of the pointer's POINTER_DATA structure.  What we'll do
                   2196: ; instead is to copy it to the rdWork structure and update it there.
                   2197: ; We'll also set up to XOR this to the screen instead of the
                   2198: ; POINTER_DATA structure.
                   2199: ;-----------------------------------------------------------------------;
                   2200: 
                   2201:         lodsw
                   2202:         mov     rdWork.rd_ptbSave, ax
                   2203: 
                   2204:         .ERRNZ  rd_ptbSave
                   2205:         .ERRNZ  (SIZE POINTB) - 2
                   2206: 
                   2207:         lodsd
                   2208:         mov     rdWork.rd_ptlScreen.ptl_x, eax
                   2209: 
                   2210:         .ERRNZ  rd_ptlScreen-rd_ptbSave-2
                   2211:         .ERRNZ  ptl_x
                   2212: 
                   2213:         lodsd
                   2214:         mov     rdWork.rd_ptlScreen.ptl_y, eax
                   2215: 
                   2216:         .ERRNZ  ptl_y-ptl_x-4
                   2217: 
                   2218:         lodsw
                   2219:         mov     rdWork.rd_sizb, ax
                   2220: 
                   2221:         .ERRNZ  (SIZE SIZEB) - 2
                   2222: 
                   2223:         lodsw
                   2224:         mov     rdWork.rd_ptbWork, ax
                   2225: 
                   2226:         .ERRNZ  (SIZE POINTB) - 2
                   2227: 
                   2228:         sub     esi,SIZE RECT_DATA      ;--> to start of POINTER_DATA
                   2229: 
                   2230:         .ERRNZ  (rd_ptbWork+2)-(SIZE RECT_DATA)
                   2231: 
                   2232: ; Perform the clipping for the work area.  We know that some part of the
                   2233: ; work area exists, else we wouldn't be here with a valid rectangle.
                   2234: ; If FB_NEW_PTR is set in fbAndRead, then we want to replace it with
                   2235: ; FB_WORK_RECT, else we'll want to process any overlap rectangles.
                   2236: 
                   2237:         mov     edi, offset FLAT:rdWork
                   2238:         call    do_clipping
                   2239:         mov     bl, FB_WORK_RECT
                   2240:         mov     fbXor, bl
                   2241:         xchg    fbAndRead, bl           ;Assume only work rect to and/read
                   2242:         test    bl, FB_NEW_PTR
                   2243:         jnz     new_been_clipped
                   2244: 
                   2245:         mov     edi, offset FLAT:rdReadX
                   2246:         mov     bh, FB_READ_X
                   2247:         test    bl, bh
                   2248:         jz      @F
                   2249:         call    do_clipping
                   2250: @@:
                   2251:         mov     edi, offset FLAT:rdReadY
                   2252:         mov     bh, FB_READ_Y
                   2253:         test    bl, bh
                   2254:         jz      @F
                   2255:         call    do_clipping
                   2256: @@:
                   2257:         mov     fbAndRead, bl
                   2258: 
                   2259: new_been_clipped:
                   2260: 
                   2261:         PLAIN_RET
                   2262: 
                   2263: page
                   2264: 
                   2265: ;--------------------------Private-Routine------------------------------;
                   2266: ; do_clipping
                   2267: ;
                   2268: ; This routine performs the actual clipping of a rectangle using the
                   2269: ; passed POINTER_DATA and RECT_DATA structures.
                   2270: ;
                   2271: ; Entry:
                   2272: ;       BL  =  flag byte
                   2273: ;       BH  =  bit to clear in BL if rectangle is invisible
                   2274: ;       DL  =  pd_fb for [si]
                   2275: ;       SI --> POINTER_DATA structure
                   2276: ;       DI --> RECT_DATA structure
                   2277: ; Returns:
                   2278: ;       BL updated
                   2279: ; Error Returns:
                   2280: ;       None
                   2281: ; Registers Preserved:
                   2282: ;       DX,SI,DI,BP
                   2283: ; Registers Destroyed:
                   2284: ;       AX,BH,CX
                   2285: ; Calls:
                   2286: ;       None
                   2287: ;
                   2288: ;-----------------------------------------------------------------------;
                   2289: 
                   2290: 
                   2291:         align   4
                   2292: do_clipping:
                   2293: 
                   2294:         .ERRNZ  pd_rd                   ;Must be at offset 0
                   2295: 
                   2296:         xor     eax, eax
                   2297:         test    dl, PD_CLIP_BOTTOM OR PD_CLIP_TOP
                   2298:         jz      y_clipping_done
                   2299:         mov     ecx, [edi].rd_ptlScreen.ptl_y
                   2300:         js      clip_on_bottom_eh?
                   2301: 
                   2302:         .ERRNZ  PD_CLIP_BOTTOM-10000000b
                   2303: 
                   2304: ;-----------------------------------------------------------------------;
                   2305: ; Top clipping may have to be performed for this rectangle.
                   2306: ;-----------------------------------------------------------------------;
                   2307: 
                   2308: clip_on_top:
                   2309:         neg     ecx                        ;If it was negative, then must clip
                   2310:         jle     y_clipping_done            ;Was positive, no clipping needed
                   2311:         sub     [edi].rd_sizb.sizb_cy, cl  ;Compute new height
                   2312:         jle     clear_visible_bit          ;Clipped away, nothing visible
                   2313:         add     [edi].rd_ptbWork.ptb_y, cl ;Move down in work area
                   2314:         add     cl, [edi].rd_ptbSave.ptb_y ;Move down in save area
                   2315:         and     cl, SAVE_BUFFER_HEIGHT-1
                   2316:         mov     [edi].rd_ptbSave.ptb_y, cl
                   2317:         mov     [edi].rd_ptlScreen.ptl_y, eax
                   2318:         jmp     finish_y_clipping
                   2319: 
                   2320: 
                   2321: ;-----------------------------------------------------------------------;
                   2322: ; Bottom clipping may have to be performed for this rectangle.
                   2323: ;-----------------------------------------------------------------------;
                   2324: 
                   2325: clip_on_bottom_eh?:
                   2326:         mov     al, [edi].rd_sizb.sizb_cy
                   2327:         add     ecx, eax
                   2328:         sub     ecx, cyScreen
                   2329:         jle     finish_y_clipping       ;EAX = amount to clip if positive
                   2330:         sub     al, cl                  ;Compute new height
                   2331:         jle     clear_visible_bit       ;Clipped away, nothing visible
                   2332:         mov     [edi].rd_sizb.sizb_cy, al
                   2333: finish_y_clipping:
                   2334:         xor     eax, eax
                   2335: y_clipping_done:
                   2336: 
                   2337: 
                   2338:         test    dl, PD_CLIP_LEFT OR PD_CLIP_RIGHT
                   2339:         jz      x_clipping_done
                   2340:         mov     ecx, [edi].rd_ptlScreen.ptl_x
                   2341:         test    dl, PD_CLIP_RIGHT
                   2342:         jnz     clip_on_rhs
                   2343: 
                   2344: ;-----------------------------------------------------------------------;
                   2345: ; lhs clipping may have to be performed for this rectangle.
                   2346: ;-----------------------------------------------------------------------;
                   2347: 
                   2348: clip_on_lhs:
                   2349:         neg     ecx                     ;If it was negative, then must clip
                   2350:         jle     x_clipping_done         ;Was positive, no clipping needed
                   2351:         sub     [edi].rd_sizb.sizb_cx, cl ;Compute new width
                   2352:         jle     clear_visible_bit       ;Clipped away, nothing visible
                   2353:         add     [edi].rd_ptbWork.ptb_x, cl;Move right in work area
                   2354:         add     cl, [edi].rd_ptbSave.ptb_x;Move right in save area
                   2355:         and     cl, SAVE_BUFFER_WIDTH-1
                   2356:         mov     [edi].rd_ptbSave.ptb_x, cl
                   2357:         mov     [edi].rd_ptlScreen.ptl_x, eax
                   2358:         jmp     x_clipping_done
                   2359: 
                   2360: 
                   2361: ;-----------------------------------------------------------------------;
                   2362: ; rhs clipping may have to be performed for this rectangle.
                   2363: ;-----------------------------------------------------------------------;
                   2364: 
                   2365: clip_on_rhs:
                   2366:         mov     al,[edi].rd_sizb.sizb_cx
                   2367:         add     ecx,eax
                   2368:         sub     ecx,lNextScan
                   2369:         jle     x_clipping_done         ;EAX = amount to clip if positive
                   2370:         sub     al,cl                   ;Compute new height
                   2371:         jle     clear_visible_bit       ;Clipped away, nothing visible
                   2372:         mov     [edi].rd_sizb.sizb_cx, al
                   2373: x_clipping_done:
                   2374:         xor     bh,bh                   ;0 to cancel following XOR
                   2375: 
                   2376: clear_visible_bit:
                   2377:         xor     bl,bh                   ;Update visible bit
                   2378:         PLAIN_RET
                   2379: 
                   2380: page
                   2381: 
                   2382: ;--------------------------Private-Routine------------------------------;
                   2383: ; xor_to_screen
                   2384: ;
                   2385: ;   The work area is XORed with the XOR mask and placed on the screen
                   2386: ;
                   2387: ; Entry:
                   2388: ;       AL = fbXor
                   2389: ; Returns:
                   2390: ;       None
                   2391: ; Error Returns:
                   2392: ;       No error return.
                   2393: ; Registers Preserved:
                   2394: ;       BP
                   2395: ; Registers Destroyed:
                   2396: ;       AX,BX,CX,DX,SI,DI,FLAGS
                   2397: ; Calls:
                   2398: ;       None
                   2399: ;
                   2400: ;-----------------------------------------------------------------------;
                   2401: 
                   2402:         .ERRNZ  pd_rd                   ;Must be at offset 0
                   2403: 
                   2404:         align   4
                   2405: xor_to_screen:
                   2406:         xor     ebx, ebx                ;Zero will be useful soon
                   2407:         shr     al, 1                   ;Set 'C' to FB_WORK_RECT bit
                   2408: 
                   2409:         .ERRNZ  FB_WORK_RECT-00000001b
                   2410: 
                   2411: ;-----------------------------------------------------------------------;
                   2412: ; Program the EGA for XOR mode.  This will be done using M_PROC_WRITE,
                   2413: ; M_DATA_READ, DR_XOR, and setting GRAF_BIT_MASK to FF.  The normal
                   2414: ; sequence of events will have left the bitmask register with 00h and
                   2415: ; the mode register in AND mode.
                   2416: ;-----------------------------------------------------------------------;
                   2417: 
                   2418:         mov     dx, EGA_BASE + GRAF_ADDR
                   2419:         mov     ax, 0FF00h + GRAF_BIT_MASK
                   2420:         out     dx, ax                  ;Enable all bits
                   2421:         mov     ax, DR_XOR SHL 8 + GRAF_DATA_ROT
                   2422:         out     dx, ax
                   2423: 
                   2424: ;-----------------------------------------------------------------------;
                   2425: ; Compute the offset from the start of the work area and the XOR mask
                   2426: ; (its the same value).  If we're to use the new pointer's rectangle,
                   2427: ; then this offset is zero.
                   2428: ;-----------------------------------------------------------------------;
                   2429: 
                   2430:         mov     esi,ppdNew              ;assume new pointer is in use
                   2431:         jnc     have_xor_mask_offset    ;EBX = 0 is offset
                   2432: 
                   2433:         .ERRNZ  FB_WORK_RECT-00000001b
                   2434:         .ERRE   FB_NEW_PTR-00000001b
                   2435: 
                   2436:         mov     esi,offset FLAT:rdWork          ;The work area (we be clipping)
                   2437:         movzx   eax,WORD PTR [esi].rd_ptbWork   ;Get origin in work area
                   2438:         xchg    ah, bl                  ;BX = ptbWork.ptb_y, AX = ptbWork.ptb_x
                   2439:         add     eax,ebx                         ;*1 + X component
                   2440:         add     ebx,ebx                         ;*2
                   2441:         add     ebx,ebx                         ;*4
                   2442:         add     ebx,eax                         ;*5 + X = start from work/mask
                   2443: 
                   2444:         .ERRNZ  WORK_WIDTH-5
                   2445: 
                   2446: have_xor_mask_offset:
                   2447: 
                   2448: 
                   2449: ; Map the proper bank into the destination window for the top destination
                   2450: ; scan line.
                   2451: 
                   2452:         mov     edi,pdsurf
                   2453:         mov     edx,[esi].rd_ptlScreen.ptl_y
                   2454:         mov     ulCurrentTopScan,edx    ;remember where the top dest scan is
                   2455:         cmp     edx,[edi].dsurf_rcl2WindowClipD.yTop ;is xor top less than
                   2456:                                                      ; current dest bank?
                   2457:         jl      short xts_map_init_bank              ;yes, map in proper bank
                   2458:         cmp     edx,[edi].dsurf_rcl2WindowClipD.yBottom ;xor top greater than
                   2459:                                                         ; current dest bank?
                   2460:         jl      short xts_init_bank_mapped      ;no, proper bank already mapped
                   2461: xts_map_init_bank:
                   2462: 
                   2463: ; Map bank containing the top destination (screen) scan line into dest window.
                   2464: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   2465: 
                   2466:         ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
                   2467:                 <edi,edx,JustifyTop,MapDestBank>
                   2468: 
                   2469: xts_init_bank_mapped:
                   2470: 
                   2471: 
                   2472: ; Map the cursor bank into the source window.
                   2473: 
                   2474:         mov     edx,ulPtrBankScan       ;scan line at end of cursor work bank
                   2475:         cmp     edx,[edi].dsurf_rcl2WindowClipS.yTop ;is cursor scan less than
                   2476:                                                      ; current source bank?
                   2477:         jl      short xts_map_ptr_bank               ;yes, map in proper bank
                   2478:         cmp     edx,[edi].dsurf_rcl2WindowClipS.yBottom ;cursor scan greater
                   2479:                                                         ; than current source
                   2480:                                                         ; bank?
                   2481:         jl      short xts_ptr_bank_mapped       ;no, proper bank already mapped
                   2482: xts_map_ptr_bank:
                   2483: 
                   2484: ; Map cursor work bank into source window.
                   2485: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   2486: 
                   2487:         ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
                   2488:                 <edi,edx,JustifyBottom,MapSourceBank>
                   2489: 
                   2490: xts_ptr_bank_mapped:
                   2491: 
                   2492: 
                   2493: ; Compute the screen address of this rectangle and get its size
                   2494: 
                   2495:         mov     ecx,[edi].dsurf_pvBitmapStart2WindowD ;start of screen bitmap
                   2496:         mov     edi,lNextScan                   ;width of screen bitmap
                   2497:         imul    edi,[esi].rd_ptlScreen.ptl_y    ;offset of dest start in screen
                   2498:         add     edi,[esi].rd_ptlScreen.ptl_x    ; buffer
                   2499:         add     edi,ecx                         ;virtual address of dest start
                   2500: 
                   2501:         mov     cx,[esi].rd_sizb                ;CH = scans to copy
                   2502:                                                 ; CL = bytes across to copy
                   2503: 
                   2504:         .ERRNZ  sizb_cy-sizb_cx-1
                   2505: 
                   2506: ;-----------------------------------------------------------------------;
                   2507: ; To save incrementing the work area pointer (BX), subtract the XOR
                   2508: ; mask pointer off of it.  Then use [BX][SI] for addressing into the
                   2509: ; XOR mask.  As SI is incremented, BX will effectively be incremented.
                   2510: ; We could not do this if the XOR mask and the work area were different
                   2511: ; widths.
                   2512: ;
                   2513: ; Finish computing the pointer to the XOR mask and the delta from the
                   2514: ; XOR mask to the work area.
                   2515: ;-----------------------------------------------------------------------;
                   2516: 
                   2517:         mov     esi,pAndXor             ;set address of XOR mask
                   2518:         lea     esi,[esi][ebx][base_xor_masks-base_and_masks]
                   2519:         add     ebx,pPtrWork            ;start src offset in bitmap
                   2520:         mov     eax,pdsurf
                   2521:         add     ebx,[eax].dsurf_pvBitmapStart2WindowS ;start src virtual addr
                   2522:         sub     ebx,esi                 ;fudge back so we get away with one
                   2523:                                         ; increment
                   2524: 
                   2525: ; Calculate the number of scans we'll do in this bank.
                   2526: 
                   2527:         mov     edx,[eax].dsurf_rcl2WindowClipD.yBottom
                   2528:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   2529:                                         ; the initial bank
                   2530:         sub     eax,eax
                   2531:         mov     al,ch                   ;total # of scans to copy
                   2532:         cmp     eax,edx                 ;can we handle all remaining scans in
                   2533:                                         ; this bank?
                   2534:         jb      short @F                ;yes
                   2535:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   2536: @@:
                   2537:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   2538:         sub     ch,al                   ;count this bank's scans off total
                   2539:         mov     byte ptr cjTotalScans,ch ;remember # of scans after this bank
                   2540:         mov     ch,al                   ;# of scans to do in this bank
                   2541: 
                   2542: ; Compute the delta to the start of the next scanline of the XOR mask
                   2543: ; and the work area, and the next scan of the screen
                   2544: 
                   2545:         sub     eax,eax
                   2546:         mov     al,cl                   ;width to copy in bytes
                   2547:         mov     edx,WORK_WIDTH
                   2548:         sub     edx,eax                 ;offset from end of one source scan to
                   2549:         mov     ulNextSrcScan,edx       ; start of next
                   2550:         add     edx,lNextScan           ;offset from end of one dest scan to
                   2551:         sub     edx,WORK_WIDTH          ; start of next
                   2552: 
                   2553:         lea     eax,[eax*4]
                   2554:         neg     eax
                   2555:         add     eax,offset FLAT:xor_to_screen_width_0
                   2556: 
                   2557:         push    ebp                     ;remember stack frame pointer
                   2558:         mov     ebp,ulNextSrcScan       ;offset to next XOR scan
                   2559:         jmp     eax
                   2560: 
                   2561:         .ERRNZ  WORK_WIDTH-5
                   2562: ;-----------------------------------------------------------------------;
                   2563: ; Register usage for the loop will be:
                   2564: ;
                   2565: ;       AX    = loop starting address
                   2566: ;       BX    = offset off [si] to the work area
                   2567: ;       CH    = height
                   2568: ;       DX    = delta to next scan of the destination
                   2569: ;       SI    --> XOR mask
                   2570: ;       DI    --> Destination
                   2571: ;       BP    = offset to next byte of XOR mask, next scan of work area
                   2572: ;-----------------------------------------------------------------------;
                   2573: 
                   2574:         align   4
                   2575: xor_to_screen_width_5:
                   2576:         cmp     al, [ebx][esi]          ;Load latches from work area
                   2577:         movsb                           ;XOR to the screen
                   2578: xor_to_screen_width_4:
                   2579:         cmp     al, [ebx][esi]
                   2580:         movsb
                   2581: xor_to_screen_width_3:
                   2582:         cmp     al, [ebx][esi]
                   2583:         movsb
                   2584: xor_to_screen_width_2:
                   2585:         cmp     al, [ebx][esi]
                   2586:         movsb
                   2587: xor_to_screen_width_1:
                   2588:         cmp     al, [ebx][esi]
                   2589:         movsb
                   2590: xor_to_screen_width_0:
                   2591: 
                   2592:         .ERRNZ  xor_to_screen_width_0-xor_to_screen_width_1-4
                   2593:         .ERRNZ  xor_to_screen_width_1-xor_to_screen_width_2-4
                   2594:         .ERRNZ  xor_to_screen_width_2-xor_to_screen_width_3-4
                   2595:         .ERRNZ  xor_to_screen_width_3-xor_to_screen_width_4-4
                   2596:         .ERRNZ  xor_to_screen_width_4-xor_to_screen_width_5-4
                   2597: 
                   2598:         add     esi, ebp                ;--> next scan's XOR mask, work addr
                   2599:         add     edi, edx                ;--> next scan's destination
                   2600:         dec     ch                      ;count down lines in this bank
                   2601:         jz      short @F                ;no more lines in this bank
                   2602:         jmp     eax                     ;do the next line in this bank
                   2603: 
                   2604:         align   4
                   2605: @@:                                     ;done with bank
                   2606:         pop     ebp                     ;retrieve stack frame pointer
                   2607:         cmp     byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
                   2608:         jz      short xts_done          ;no, we're done
                   2609:                                         ;advance to next dest bank and continue
                   2610:                                         ; XORing
                   2611:         push    eax                     ;preserve entry vector
                   2612:         push    edx                     ;preserve dest next scan
                   2613:         mov     eax,pdsurf
                   2614:         sub     edi,[eax].dsurf_pvBitmapStart2WindowD
                   2615:                                         ;calculate the destination offset
                   2616:                                         ; within the bitmap, because the start
                   2617:                                         ; address is about to move
                   2618:         mov     edx,ulCurrentTopScan
                   2619: 
                   2620: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   2621: 
                   2622:         ptrCall <dword ptr [eax].dsurf_pfnBankControl2Window>, \
                   2623:                 <eax,edx,JustifyTop,MapDestBank> ;map in the next dest bank
                   2624: 
                   2625:         mov     eax,pdsurf
                   2626:         add     edi,[eax].dsurf_pvBitmapStart2WindowD
                   2627:                                         ;add back in the bitmap start address
                   2628:                                         ; to yield the virtual dest address
                   2629:         mov     edx,[eax].dsurf_rcl2WindowClipD.yBottom
                   2630:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   2631:                                         ; the new bank
                   2632:         sub     eax,eax
                   2633:         mov     al,byte ptr cjTotalScans ;remaining scan count
                   2634:         cmp     eax,edx                 ;can we handle all remaining scans in
                   2635:                                         ; this bank?
                   2636:         jb      short @F                ;yes
                   2637:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   2638: @@:
                   2639:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   2640:         sub     byte ptr cjTotalScans,al ;count this bank's scans off total
                   2641:         mov     ch,al                   ;# of scans to do in this bank
                   2642: 
                   2643:         pop     edx                     ;restore dest next scan
                   2644:         pop     eax                     ;restore entry vector
                   2645: 
                   2646:         push    ebp                     ;remember stack frame pointer
                   2647:         mov     ebp,ulNextSrcScan       ;offset to next XOR scan
                   2648:         jmp     eax                     ;do the next block of scans
                   2649: 
                   2650: xts_done:
                   2651:         PLAIN_RET
                   2652: 
                   2653: page
                   2654: ;--------------------------Private-Routine------------------------------;
                   2655: ; color_pointer_to_screen
                   2656: ;
                   2657: ;   The color pointer is output to the screen using AND/XOR/COLOR masks.
                   2658: ;
                   2659: ; Entry:
                   2660: ;       None
                   2661: ; Returns:
                   2662: ;       None
                   2663: ; Error Returns:
                   2664: ;       No error return.
                   2665: ; Registers Preserved:
                   2666: ;       BP
                   2667: ; Registers Destroyed:
                   2668: ;       AX,BX,CX,DX,SI,DI,FLAGS
                   2669: ; Calls:
                   2670: ;       None
                   2671: ;
                   2672: ;-----------------------------------------------------------------------;
                   2673: 
                   2674:         align   4
                   2675: color_pointer_to_screen:
                   2676: 
                   2677:         .ERRNZ  pd_rd                   ;Must be at offset 0
                   2678: 
                   2679: ; Set up variables that don't change from plane to plane in the outer loop
                   2680: 
                   2681:         mov     esi,ppdNew
                   2682:         test    fbXor,FB_WORK_RECT
                   2683:         jz      short cps_have_pointer_rect
                   2684:         mov     esi,offset FLAT:rdWork  ;the work area (we be clipping)
                   2685: cps_have_pointer_rect:
                   2686:         mov     prclSource,esi
                   2687: 
                   2688: ; Map the proper bank into the destination window for the top destination
                   2689: ; scan line.
                   2690: 
                   2691:         mov     ebx,pdsurf
                   2692:         mov     edx,[esi].rd_ptlScreen.ptl_y
                   2693:         mov     ulCurrentTopScan,edx    ;remember where the top dest scan is
                   2694:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is copy top less than
                   2695:                                                      ; current dest bank?
                   2696:         jl      short cpts_map_init_bank             ;yes, map in proper bank
                   2697:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;copy top greater than
                   2698:                                                         ; current dest bank?
                   2699:         jl      short cpts_init_bank_mapped     ;no, proper bank already mapped
                   2700: cpts_map_init_bank:
                   2701: 
                   2702: ; Map bank containing the top destination (screen) scan line into dest window.
                   2703: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   2704: 
                   2705:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
                   2706:                 <ebx,edx,JustifyTop,MapDestBank>
                   2707: 
                   2708: cpts_init_bank_mapped:
                   2709: 
                   2710: 
                   2711: ; Map the cursor bank into the source window.
                   2712: 
                   2713:         mov     edx,ulPtrBankScan       ;scan line at end of cursor work bank
                   2714:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is cursor scan less than
                   2715:                                                      ; current source bank?
                   2716:         jl      short cpts_map_ptr_bank              ;yes, map in proper bank
                   2717:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;cursor scan greater
                   2718:                                                         ; than current source
                   2719:                                                         ; bank?
                   2720:         jl      short cpts_ptr_bank_mapped      ;no, proper bank already mapped
                   2721: cpts_map_ptr_bank:
                   2722: 
                   2723: ; Map cursor work bank into source window.
                   2724: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   2725: 
                   2726:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
                   2727:                 <ebx,edx,JustifyBottom,MapSourceBank>
                   2728: 
                   2729: cpts_ptr_bank_mapped:
                   2730: 
                   2731: 
                   2732: ; Offset to next screen scan, minus the width of the work area, will
                   2733: ; come in handy in the inner loop.
                   2734: 
                   2735:         mov     eax,lNextScan   ;width of screen bitmap
                   2736:         mov     edi,eax         ;set aside for computing the screen address
                   2737:         sub     eax,WORK_WIDTH
                   2738:         mov     ulScanMinusWorkWidth,eax
                   2739: 
                   2740: ; Compute the screen address of the rectangle in this bank
                   2741: 
                   2742:         imul    edi,[esi].rd_ptlScreen.ptl_y    ;offset of dest start in screen
                   2743:         add     edi,[esi].rd_ptlScreen.ptl_x    ; buffer
                   2744:         add     edi,[ebx].dsurf_pvBitmapStart2WindowD ;virtual address of dest
                   2745:                                                       ; start
                   2746:         mov     pDest,edi
                   2747: 
                   2748: ; Remember the save source point.
                   2749: 
                   2750:         sub     eax,eax
                   2751:         mov     ax,word ptr [esi].rd_ptbSave
                   2752:         mov     jSaveSourceXY,eax
                   2753:         mov     byte ptr jNextSaveSourceY,ah
                   2754: 
                   2755: 
                   2756: ; Remember the work source point.
                   2757: 
                   2758:         mov     ax,word ptr [esi].rd_ptbWork
                   2759:         mov     jWorkSourceXY,eax
                   2760:         mov     byte ptr jNextWorkSourceY,ah
                   2761: 
                   2762: 
                   2763: ; Calculate the number of scans we'll do in this bank.
                   2764: 
                   2765:         mov     edx,[ebx].dsurf_rcl2WindowClipD.yBottom
                   2766:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   2767:                                         ; the initial bank
                   2768:         mov     ch,byte ptr [esi].rd_sizb+1 ;total # of scans to copy
                   2769:         sub     eax,eax
                   2770:         mov     al,ch
                   2771:         cmp     eax,edx                 ;can we handle all remaining scans in
                   2772:                                         ; this bank?
                   2773:         jb      short @F                ;yes
                   2774:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   2775: @@:
                   2776:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   2777:         add     byte ptr jNextSaveSourceY,al ;top save source scan for next bank
                   2778:         add     byte ptr jNextWorkSourceY,al ;top work source scan for next bank
                   2779:         sub     ch,al                   ;count this bank's scans off total
                   2780:         mov     byte ptr cjTotalScans,ch ;remember # of scans after this bank
                   2781:         mov     byte ptr jScansInBank,al ;# of scans to do in this bank
                   2782: 
                   2783: ; Set the virtual address of the save area
                   2784: 
                   2785:         mov     eax,[ebx].dsurf_pvBitmapStart2WindowS ;start of source bitmap
                   2786:         add     eax,pPtrSave            ;virtual address of save area
                   2787:         mov     pWorkingSave,eax
                   2788: 
                   2789: ; Loop through banks that this cursor spans
                   2790: 
                   2791: cpts_bank_loop:
                   2792: 
                   2793: ; Initial plane is plane 3
                   2794: 
                   2795:         mov     iPlaneMask,MM_C3
                   2796: 
                   2797: ;-----------------------------------------------------------------------;
                   2798: ; Program the VGA for SET mode.  This will be done using M_PROC_WRITE,
                   2799: ; M_DATA_READ, DR_SET, and setting GRAF_BIT_MASK to FF.  The normal
                   2800: ; sequence of events will have left the bitmask register with 00h and
                   2801: ; the mode register in AND mode.
                   2802: ;-----------------------------------------------------------------------;
                   2803: 
                   2804:         mov     dx,EGA_BASE + GRAF_ADDR
                   2805:         mov     ax,0FF00h + GRAF_BIT_MASK
                   2806:         out     dx,ax                   ;enable all bits
                   2807:         mov     ax,DR_SET SHL 8 + GRAF_DATA_ROT
                   2808:         out     dx,ax
                   2809:         mov     al,GRAF_READ_MAP
                   2810:         out     dx,al   ;leave the GC Index pointing to the Read Map reg
                   2811: 
                   2812: cps_do_next_plane:
                   2813: 
                   2814: ; Set write plane enable register to the ONE plane we will alter
                   2815: 
                   2816:         mov     al,byte ptr iPlaneMask          ;set Map Mask
                   2817:         mov     dx,EGA_BASE + SEQ_DATA
                   2818:         out     dx,al
                   2819: 
                   2820: ; Set read plane to plane to read from
                   2821: 
                   2822:         shr     al,1                    ;map plane into ReadMask
                   2823:         cmp     al,100b                 ;set Carry if not C3 (plane 3)
                   2824:         adc     al,-1                   ;sub 1 only if C3
                   2825:         mov     dl,GRAF_DATA
                   2826:         out     dx,al
                   2827: 
                   2828:         mov     esi,prclSource          ;point to source rect
                   2829:         mov     edi,pDest               ;point to initial dest byte
                   2830: 
                   2831:         mov     eax,jSaveSourceXY
                   2832:         mov     edx,jWorkSourceXY
                   2833: 
                   2834:         .ERRNZ  ptb_y-ptb_x-1
                   2835: 
                   2836:         mov     cl,byte ptr [esi].rd_sizb
                   2837: 
                   2838:         .ERRNZ  sizb_cy-sizb_cx-1
                   2839: 
                   2840:         mov     bl,al                   ;see if save area is contiguous
                   2841:         add     bl,cl
                   2842:         sub     bl,SAVE_BUFFER_WIDTH    ;BL = is overhang
                   2843:         jle     short call_cps_do_a_pass ;no overhang
                   2844: 
                   2845:         sub     cl,bl                   ;set X extent for pass 1
                   2846:         mov     bh,cl                   ;need it for pass 2
                   2847:         mov     ch,byte ptr jScansInBank ;# of scans to do in this bank
                   2848:         push    ebx
                   2849:         call    cps_do_a_pass           ;process first half
                   2850:         pop     ebx
                   2851: 
                   2852:         mov     esi,prclSource          ;point to source rect
                   2853:         mov     edi,pDest               ;point to initial dest byte
                   2854: 
                   2855:         mov     eax,jSaveSourceXY
                   2856:         mov     edx,jWorkSourceXY
                   2857: 
                   2858:         .ERRNZ  ptb_y-ptb_x-1
                   2859: 
                   2860:         mov     cl,byte ptr [esi].rd_sizb
                   2861: 
                   2862:         .ERRNZ  sizb_cy-sizb_cx-1
                   2863: 
                   2864:         add     dl,bh                   ;move right in work area
                   2865:         mov     cl,bl                   ;set new extent
                   2866:         xor     al,al                   ;X origin in save area is 0
                   2867:         movzx   ebx,bh                  ;move right in destination area
                   2868:         add     edi,ebx
                   2869: 
                   2870: call_cps_do_a_pass:
                   2871:         mov     ch,byte ptr jScansInBank ;# of scans to do in this bank
                   2872:         call    cps_do_a_pass           ;process second half (or the whole
                   2873:                                         ; color cursor, if no overhang)
                   2874: 
                   2875:         shr     iPlaneMask,1
                   2876:         jnc     cps_do_next_plane
                   2877: 
                   2878:         .ERRNZ  MM_C0-00000001b
                   2879:         .ERRNZ  MM_C1-00000010b
                   2880:         .ERRNZ  MM_C2-00000100b
                   2881:         .ERRNZ  MM_C3-00001000b
                   2882: 
                   2883:                                         ;we've done all planes in this bank
                   2884:         cmp     byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
                   2885:         jz      short cpts_done         ;no, we're done
                   2886:                                         ;advance to next dest bank and continue
                   2887:                                         ; XORing
                   2888: 
                   2889: ; Advance the source Y coordinates to match the bank advance we're about to do.
                   2890: 
                   2891:         mov     al,byte ptr jNextSaveSourceY
                   2892:         mov     byte ptr jSaveSourceXY+1,al
                   2893:         mov     al,byte ptr jNextWorkSourceY
                   2894:         mov     byte ptr jWorkSourceXY+1,al
                   2895: 
                   2896: ; Advance to the next dest bank.
                   2897: 
                   2898:         mov     ebx,pdsurf
                   2899:         mov     edx,ulCurrentTopScan
                   2900: 
                   2901: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   2902: 
                   2903:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
                   2904:                 <ebx,edx,JustifyTop,MapDestBank> ;map in the next dest bank
                   2905: 
                   2906: ; Compute the screen start address of the rectangle in this bank
                   2907: 
                   2908:         mov     esi,prclSource                  ;point to source rect
                   2909:         mov     edi,lNextScan                   ;width of screen bitmap
                   2910:         imul    edi,ulCurrentTopScan            ;offset of dest start in screen
                   2911:         add     edi,[esi].rd_ptlScreen.ptl_x    ; buffer
                   2912:         add     edi,[ebx].dsurf_pvBitmapStart2WindowD ;virtual address of dest
                   2913:                                                       ; start
                   2914:         mov     pDest,edi
                   2915: 
                   2916:         mov     edx,[ebx].dsurf_rcl2WindowClipD.yBottom
                   2917:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   2918:                                         ; the new bank
                   2919:         sub     eax,eax
                   2920:         mov     al,byte ptr cjTotalScans ;remaining scan count
                   2921:         cmp     eax,edx                 ;can we handle all remaining scans in
                   2922:                                         ; this bank?
                   2923:         jb      short @F                ;yes
                   2924:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   2925: @@:
                   2926:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   2927:         add     byte ptr jNextSaveSourceY,al ;top save source scan for next bank
                   2928:         add     byte ptr jNextWorkSourceY,al ;top work source scan for next bank
                   2929:         sub     byte ptr cjTotalScans,al ;count this bank's scans off total
                   2930:         mov     byte ptr jScansInBank,al ;# of scans to do in this bank
                   2931: 
                   2932:         jmp     cpts_bank_loop          ;do the next block of scans
                   2933: 
                   2934: cpts_done:
                   2935:         PLAIN_RET
                   2936: 
                   2937: page
                   2938: ;--------------------------Private-Routine------------------------------;
                   2939: ; cps_do_a_pass
                   2940: ;
                   2941: ; Output one plane of the color pointer to the screen using
                   2942: ; AND/XOR/COLOR masks. Does not handle bank spanning; that is taken care
                   2943: ; of in color_pointer_to_screen.
                   2944: ;
                   2945: ; Entry:
                   2946: ;       AH  = ptbSave.ptb_y, AL = ptbSave.ptb_x
                   2947: ;       DH  = ptbWork.ptb_y, DL = ptbWork.ptb_x
                   2948: ;       CL  = x bytes to process
                   2949: ;       CH  = y scans to process
                   2950: ;       EDI --> Destination   (screen area)
                   2951: ;       EBP = stack frame
                   2952: ;       VGA set up to enable writes to proper plane
                   2953: ; Returns:
                   2954: ;       None
                   2955: ; Error Returns:
                   2956: ;       No error return.
                   2957: ; Registers Preserved:
                   2958: ;       EBP
                   2959: ; Registers Destroyed:
                   2960: ;       EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
                   2961: ; Calls:
                   2962: ;       None
                   2963: ;
                   2964: ;-----------------------------------------------------------------------;
                   2965: 
                   2966:         align   4
                   2967: cps_do_a_pass:
                   2968: 
                   2969: ;-----------------------------------------------------------------------;
                   2970: ; Compute the offset within the save area.  Note that this is relative
                   2971: ; to screen_buf.
                   2972: ; AH = ptbSave.ptb_y, AL = ptbSave.ptb_x
                   2973: ;-----------------------------------------------------------------------;
                   2974: 
                   2975:         shl     ah,3
                   2976:         add     al,ah                   ;y * 8 + x
                   2977:         xor     ah,ah
                   2978:         cwde
                   2979:         mov     ulOffsetSave,eax
                   2980: 
                   2981:         .ERRNZ  SAVE_BUFFER_WIDTH-8
                   2982:         .ERRNZ  SAVE_BUFFER_HEIGHT-32
                   2983: 
                   2984:         mov     esi,pWorkingSave        ;point to the save area
                   2985:         add     esi,eax                 ;ESI --> start address in save area
                   2986: 
                   2987: 
                   2988: ;-----------------------------------------------------------------------;
                   2989: ; Compute the offset within the AND/XOR masks.
                   2990: ; DH = ptbWork.ptb_y, DL = ptbWork.ptb_x
                   2991: ;-----------------------------------------------------------------------;
                   2992: 
                   2993:         xor     ebx,ebx
                   2994:         xchg    dh,bl
                   2995:         add     edx,ebx                 ;y * 1 + x
                   2996:         add     ebx,ebx                 ;y * 2
                   2997:         add     ebx,ebx                 ;y * 4
                   2998:         add     ebx,edx                 ;y * 5 + x
                   2999:         mov     ulOffsetMask,ebx
                   3000:         add     ebx,pAndXor             ;EBX --> start address of AND mask
                   3001:         sub     ebx,edi                 ;make EBX relative to EDI
                   3002: 
                   3003: ;-----------------------------------------------------------------------;
                   3004: ; Compute the delta to the start of the next scanline of destination
                   3005: ; screen area
                   3006: ;-----------------------------------------------------------------------;
                   3007: 
                   3008:         mov     al, cl
                   3009:         movsx   eax, al
                   3010:         mov     edx,lNextScan
                   3011:         sub     edx,eax
                   3012:         mov     ulDeltaScreen,edx       ;delta to next scan of screen area
                   3013: 
                   3014: ;-----------------------------------------------------------------------;
                   3015: ; Calculate EDX = jump table address
                   3016: ;-----------------------------------------------------------------------;
                   3017: 
                   3018:         mov     edx,color_to_screen_entry_table[eax*4]
                   3019: 
                   3020:         .ERRNZ  WORK_WIDTH-5
                   3021: 
                   3022: ;-----------------------------------------------------------------------;
                   3023: ; Compute the offset within the COLOR mask.
                   3024: ;-----------------------------------------------------------------------;
                   3025: 
                   3026:         push    ebp                     ;need an extra register
                   3027:         mov     al,byte ptr iPlaneMask  ;AL --> iPlaneMask
                   3028:         mov     ebp,ulOffsetMask        ;EBP --> usoffset_mask
                   3029:         add     ebp,pColor              ;EBP --> start address of COLOR mask
                   3030:         shr     al,1
                   3031:         jz      @F
                   3032:         add     ebp,MASK_LENGTH
                   3033:         shr     al,1
                   3034:         jz      @F
                   3035:         add     ebp,MASK_LENGTH
                   3036:         shr     al,1
                   3037:         jz      @F
                   3038:         add     ebp,MASK_LENGTH
                   3039: @@:
                   3040:         sub     ebp,edi                 ;make BP relative
                   3041: 
                   3042:         jmp     edx
                   3043: 
                   3044: ;-----------------------------------------------------------------------;
                   3045: ; Register usage for the loop will be:
                   3046: ;
                   3047: ;       EBX   = offset off EDI to the AND mask
                   3048: ;       CH    = height
                   3049: ;       EDX   = loop starting address
                   3050: ;       ESI   --> Source        (save area)
                   3051: ;       EDI   --> Destination   (screen area)
                   3052: ;       EBP   = offset off EDI to the COLOR mask
                   3053: ;-----------------------------------------------------------------------;
                   3054: 
                   3055:         align   4
                   3056: color_to_screen_width_5:
                   3057:         lodsb
                   3058:         and     al,[ebx][edi]
                   3059:         xor     al,[ebp][edi]
                   3060:         stosb
                   3061: color_to_screen_width_4:
                   3062:         lodsb
                   3063:         and     al,[ebx][edi]
                   3064:         xor     al,[ebp][edi]
                   3065:         stosb
                   3066: color_to_screen_width_3:
                   3067:         lodsb
                   3068:         and     al,[ebx][edi]
                   3069:         xor     al,[ebp][edi]
                   3070:         stosb
                   3071: color_to_screen_width_2:
                   3072:         lodsb
                   3073:         and     al,[ebx][edi]
                   3074:         xor     al,[ebp][edi]
                   3075:         stosb
                   3076: color_to_screen_width_1:
                   3077:         lodsb
                   3078:         and     al,[ebx][edi]
                   3079:         xor     al,[ebp][edi]
                   3080:         stosb
                   3081: color_to_screen_width_0:
                   3082: 
                   3083:         mov     eax,ebp                 ;EAX --> next scan's COLOR mask
                   3084:         pop     ebp
                   3085:         sub     eax,ulScanMinusWorkWidth
                   3086: 
                   3087: ; WE HAVE NO SPARE REGISTERS HERE
                   3088: 
                   3089:         xchg    eax,ulOffsetSave
                   3090:         add     al,SAVE_BUFFER_WIDTH    ;Take into account wrap around
                   3091:         mov     esi,pWorkingSave        ;point to the save area
                   3092:         add     esi,eax                 ;ESI --> next scan's save area
                   3093:         xchg    ulOffsetSave,eax
                   3094: 
                   3095:         add     edi,ulDeltaScreen       ;EDI --> next scan's screen area
                   3096:         sub     ebx,ulScanMinusWorkWidth
                   3097:                                         ;EBX --> next scan's AND mask
                   3098:         dec     ch
                   3099:         jz      cps_exit
                   3100: 
                   3101:         push    ebp
                   3102:         mov     ebp,eax                 ;EBP --> next scan's COLOR mask
                   3103:         jmp     edx                     ;do the next scan line
                   3104: 
                   3105: cps_exit:
                   3106:         PLAIN_RET
                   3107: 
                   3108: page
                   3109: 
                   3110: ;--------------------------Private-Routine------------------------------;
                   3111: ; and_into_work
                   3112: ;
                   3113: ;   All rectangles which are to be ANDed into the work area are
                   3114: ;   dispatched to the routine which will do the actual ANDing.
                   3115: ;
                   3116: ; Entry:
                   3117: ;       AL = fbAndRead
                   3118: ; Returns:
                   3119: ;       None
                   3120: ; Error Returns:
                   3121: ;       No error return.
                   3122: ; Registers Preserved:
                   3123: ;       BP
                   3124: ; Registers Destroyed:
                   3125: ;       AX,BX,CX,DX,SI,DI,FLAGS
                   3126: ; Calls:
                   3127: ;       and_from_screen
                   3128: ;       and_from_save
                   3129: ;
                   3130: ;-----------------------------------------------------------------------;
                   3131: 
                   3132:         align   4
                   3133: and_into_work:
                   3134: 
                   3135:         push    ebp
                   3136: 
                   3137: ;-----------------------------------------------------------------------;
                   3138: ; Program the EGA for AND mode.  This will be done using M_PROC_WRITE,
                   3139: ; M_DATA_READ, DR_AND, and setting GRAF_BIT_MASK to FF.  All but setting
                   3140: ; DR_AND was set by save_hw_regs.  All planes were also enabled for
                   3141: ; writing by save_hw_regs.
                   3142: ;-----------------------------------------------------------------------;
                   3143: 
                   3144:         mov     ecx, eax
                   3145:         mov     dx, EGA_BASE + GRAF_ADDR
                   3146:         mov     ax, DR_AND SHL 8 + GRAF_DATA_ROT
                   3147:         out     dx, ax
                   3148:         mov     eax, ecx
                   3149: 
                   3150: ;-----------------------------------------------------------------------;
                   3151: ; If FB_NEW_PTR or FB_WORK_AREA is set, then we only have a single
                   3152: ; rectangle to deal with, located on the screen.
                   3153: ;-----------------------------------------------------------------------;
                   3154: 
                   3155:         mov     esi, ppdNew
                   3156:         test    al, FB_NEW_PTR
                   3157:         jnz     aiw_source_is_screen
                   3158:         mov     esi, offset FLAT:rdWork
                   3159:         test    al, FB_WORK_RECT
                   3160:         jnz     aiw_source_is_screen
                   3161: 
                   3162: ; Some combination of FB_READ_X, FB_READ_Y, FB_OVERLAP exists
                   3163: 
                   3164:         test    al, FB_READ_Y
                   3165:         jz      @F
                   3166:         mov     esi, offset FLAT:rdReadY
                   3167:         call    and_from_screen
                   3168:         mov     al, fbAndRead
                   3169: @@:
                   3170: 
                   3171:         test    al, FB_READ_X
                   3172:         jz      @F
                   3173:         mov     esi, offset FLAT:rdReadX
                   3174: aiw_source_is_screen:
                   3175:         call    and_from_screen
                   3176:         mov     al, fbAndRead
                   3177: @@:
                   3178: 
                   3179:         test    al, FB_OVERLAP
                   3180:         jz      @F
                   3181:         mov     esi, offset FLAT:rdOverlap
                   3182:         call    and_from_save
                   3183: @@:
                   3184: 
                   3185:         pop     ebp
                   3186: 
                   3187:         PLAIN_RET
                   3188: 
                   3189: page
                   3190: 
                   3191: ;--------------------------Private-Routine------------------------------;
                   3192: ; and_from_screen
                   3193: ;
                   3194: ;   The screen is ANDed with the AND mask and placed into the work area
                   3195: ;
                   3196: ; Entry:
                   3197: ;       ESI --> RECT_DATA structure to use
                   3198: ;       EGA programmed for AND mode
                   3199: ; Returns:
                   3200: ;       None
                   3201: ; Error Returns:
                   3202: ;       No error return.
                   3203: ; Registers Preserved:
                   3204: ;       BP
                   3205: ; Registers Destroyed:
                   3206: ;       AX,BX,CX,DX,SI,DI,FLAGS
                   3207: ; Calls:
                   3208: ;       None
                   3209: ;
                   3210: ;-----------------------------------------------------------------------;
                   3211: 
                   3212:         align   4
                   3213: and_from_screen:
                   3214: 
                   3215:         .ERRNZ  pd_rd                   ;Must be at offset 0
                   3216: 
                   3217:         mov     eax,lNextScan
                   3218:         sub     eax,WORK_WIDTH
                   3219:         mov     ulNextSrcScan,eax       ;set the source advance offset
                   3220: 
                   3221: ;-----------------------------------------------------------------------;
                   3222: ; Map in the source and destination banks.
                   3223: ;-----------------------------------------------------------------------;
                   3224: 
                   3225: ; Map the proper bank into the source window for the top source scan line.
                   3226: 
                   3227:         mov     edi,pdsurf
                   3228:         mov     edx,[esi].rd_ptlScreen.ptl_y
                   3229:         mov     ulCurrentTopScan,edx    ;remember where the top source scan is
                   3230:         cmp     edx,[edi].dsurf_rcl2WindowClipS.yTop ;is AND top less than
                   3231:                                                      ; current source bank?
                   3232:         jl      short afscr_map_init_bank            ;yes, map in proper bank
                   3233:         cmp     edx,[edi].dsurf_rcl2WindowClipS.yBottom ;AND top greater than
                   3234:                                                         ; current source bank?
                   3235:         jl      short afscr_init_bank_mapped    ;no, proper bank already mapped
                   3236: afscr_map_init_bank:
                   3237: 
                   3238: ; Map bank containing the top destination (screen) scan line into dest window.
                   3239: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   3240: 
                   3241:         ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
                   3242:                 <edi,edx,JustifyTop,MapSourceBank>
                   3243: 
                   3244: afscr_init_bank_mapped:
                   3245: 
                   3246: 
                   3247: ; Map the cursor bank into the destination window.
                   3248: 
                   3249:         mov     edx,ulPtrBankScan       ;scan line at end of cursor work bank
                   3250:         cmp     edx,[edi].dsurf_rcl2WindowClipD.yTop ;is cursor scan less than
                   3251:                                                      ; current dest bank?
                   3252:         jl      short afscr_map_ptr_bank             ;yes, map in proper bank
                   3253:         cmp     edx,[edi].dsurf_rcl2WindowClipD.yBottom ;cursor scan greater
                   3254:                                                         ; than current dest
                   3255:                                                         ; bank?
                   3256:         jl      short afscr_ptr_bank_mapped     ;no, proper bank already mapped
                   3257: afscr_map_ptr_bank:
                   3258: 
                   3259: ; Map cursor work bank into source window.
                   3260: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   3261: 
                   3262:         ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
                   3263:                 <edi,edx,JustifyBottom,MapDestBank>
                   3264: 
                   3265: afscr_ptr_bank_mapped:
                   3266: 
                   3267: 
                   3268: ;-----------------------------------------------------------------------;
                   3269: ; Compute the screen address of this rectangle and get its size
                   3270: ;-----------------------------------------------------------------------;
                   3271: 
                   3272:         mov     ebx,lNextScan
                   3273:         imul    ebx,[esi].rd_ptlScreen.ptl_y
                   3274:         add     ebx,[esi].rd_ptlScreen.ptl_x    ;start source offset in bitmap
                   3275:         movzx   ecx,WORD PTR [esi].rd_sizb      ;CH = scans to copy
                   3276:                                                 ; CL = bytes across to copy
                   3277: 
                   3278:         .ERRNZ  sizb_cy-sizb_cx-1
                   3279: 
                   3280: ;-----------------------------------------------------------------------;
                   3281: ; Compute the offset from the start of the work area and the AND mask
                   3282: ; (it's the same value).
                   3283: ;-----------------------------------------------------------------------;
                   3284: 
                   3285:         xor     eax,eax
                   3286:         movzx   edx,WORD PTR [esi].rd_ptbWork  ;Get origin in work area
                   3287:         xchg    al,dh                   ;AX = ptbWork.ptb_y, DX = ptbWork.ptb_x
                   3288:         add     edx,eax                 ;*1 + X component
                   3289:         add     eax,eax                 ;*2
                   3290:         add     eax,eax                 ;*4
                   3291:         add     eax,edx                 ;*5 + X = start from work/mask
                   3292:         mov     edi,eax
                   3293: 
                   3294:         .ERRNZ  WORK_WIDTH-5
                   3295: 
                   3296: ;-----------------------------------------------------------------------;
                   3297: ; To save incrementing the source pointer (BX), subtract the AND
                   3298: ; mask pointer off of it.  Then use [BX][SI] for addressing into the
                   3299: ; source.  As SI is incremented, BX will effectively be incremented.
                   3300: ;
                   3301: ; The source pointer will have to be adjusted by lNextScan-sizb_cx.
                   3302: ;-----------------------------------------------------------------------;
                   3303: 
                   3304:         mov     esi,pAndXor             ;Set address of AND mask
                   3305:         add     esi,edi
                   3306:         add     edi,pPtrWork            ;start dest offset in bitmap
                   3307:         mov     eax,pdsurf
                   3308:         add     edi,[eax].dsurf_pvBitmapStart2WindowD ;start dest virtual addr
                   3309:         add     ebx,[eax].dsurf_pvBitmapStart2WindowS ;start src virtual addr
                   3310:         sub     ebx,esi                 ;fudge back so we get away with one
                   3311:                                         ; increment
                   3312: 
                   3313: ; Calculate the number of scans we'll do in this bank.
                   3314: 
                   3315:         mov     edx,[eax].dsurf_rcl2WindowClipS.yBottom
                   3316:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   3317:                                         ; the initial bank
                   3318:         sub     eax,eax
                   3319:         mov     al,ch                   ;total # of scans to copy
                   3320:         cmp     eax,edx                 ;can we handle all remaining scans in
                   3321:                                         ; this bank?
                   3322:         jb      short @F                ;yes
                   3323:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   3324: @@:
                   3325:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   3326:         sub     ch,al                   ;count this bank's scans off total
                   3327:         mov     byte ptr cjTotalScans,ch ;remember # of scans after this bank
                   3328:         mov     ch,al                   ;# of scans to do in this bank
                   3329: 
                   3330: ; Compute the delta to the start of the next scanline of the AND mask
                   3331: ; and the work area, and the next scan of the screen
                   3332: 
                   3333:         sub     eax,eax
                   3334:         mov     al,cl
                   3335:         mov     edx,WORK_WIDTH
                   3336:         sub     edx,eax
                   3337: 
                   3338: ; Look up the loop entry point, and start ANDing.
                   3339: 
                   3340:         mov     eax,and_from_screen_entry_table[eax*4] ;look up the loop entry
                   3341:         push    ebp                     ;preserve stack frame pointer
                   3342:         mov     ebp,ulNextSrcScan       ;source offset to next scan
                   3343:         jmp     eax                     ;enter the ANDing loop
                   3344: 
                   3345:         .ERRNZ  WORK_WIDTH-5
                   3346: ;-----------------------------------------------------------------------;
                   3347: ; Register usage for the loop will be:
                   3348: ;
                   3349: ;       EAX     =  loop entry address
                   3350: ;       EBX     =  offset off of SI to the screen source
                   3351: ;       CH      =  height
                   3352: ;       EDX     =  offset to next scan of AND mask & work area
                   3353: ;       ESI     --> AND mask
                   3354: ;       EDI     --> Destination in work area
                   3355: ;-----------------------------------------------------------------------;
                   3356: 
                   3357:         align   4
                   3358: and_from_screen_width_5:
                   3359:         cmp     al, [ebx][esi]          ;Load latches from work area
                   3360:         movsb                           ;AND from screen into work area
                   3361: and_from_screen_width_4:
                   3362:         cmp     al, [ebx][esi]
                   3363:         movsb
                   3364: and_from_screen_width_3:
                   3365:         cmp     al, [ebx][esi]
                   3366:         movsb
                   3367: and_from_screen_width_2:
                   3368:         cmp     al, [ebx][esi]
                   3369:         movsb
                   3370: and_from_screen_width_1:
                   3371:         cmp     al, [ebx][esi]
                   3372:         movsb
                   3373: and_from_screen_width_0:
                   3374: 
                   3375:         add     esi,edx                 ;--> next AND mask
                   3376:         add     edi,edx                 ;--> next destination
                   3377:         add     ebx,ebp                 ;--> next source
                   3378: 
                   3379:         dec     ch                      ;count down scans in this bank
                   3380:         jz      short @F                ;bank is finished
                   3381:         jmp     eax                     ;do next scan in this bank
                   3382: 
                   3383:         align   4
                   3384: @@:
                   3385:         pop     ebp                     ;restore stack frame pointer
                   3386:         cmp     byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
                   3387:         jz      short afscr_done        ;no, we're done
                   3388:                                         ;advance to next dest bank and continue
                   3389:                                         ; ANDing
                   3390:         push    eax                     ;preserve entry vector
                   3391:         push    edx                     ;preserve dest next scan
                   3392:         mov     eax,pdsurf
                   3393:         sub     ebx,[eax].dsurf_pvBitmapStart2WindowS
                   3394:                                         ;calculate the source offset within the
                   3395:                                         ; bitmap, because the start address is
                   3396:                                         ; about to move
                   3397:         mov     edx,ulCurrentTopScan
                   3398: 
                   3399: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   3400: 
                   3401:         ptrCall <dword ptr [eax].dsurf_pfnBankControl2Window>, \
                   3402:                 <eax,edx,JustifyTop,MapSourceBank> ;map in the next source bank
                   3403: 
                   3404:         mov     eax,pdsurf
                   3405:         add     ebx,[eax].dsurf_pvBitmapStart2WindowS
                   3406:                                         ;add back in the bitmap start address
                   3407:                                         ; to yield the virtual source address
                   3408:         mov     edx,[eax].dsurf_rcl2WindowClipS.yBottom
                   3409:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   3410:                                         ; the new bank
                   3411:         sub     eax,eax
                   3412:         mov     al,byte ptr cjTotalScans ;remaining scan count
                   3413:         cmp     eax,edx                 ;can we handle all remaining scans in
                   3414:                                         ; this bank?
                   3415:         jb      short @F                ;yes
                   3416:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   3417: @@:
                   3418:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   3419:         sub     byte ptr cjTotalScans,al ;count this bank's scans off total
                   3420:         mov     ch,al                   ;# of scans to do in this bank
                   3421: 
                   3422:         pop     edx                     ;restore dest next scan
                   3423:         pop     eax                     ;restore entry vector
                   3424: 
                   3425:         push    ebp                     ;preserve stack frame pointer
                   3426:         mov     ebp,ulNextSrcScan       ;source offset to next scan
                   3427:         jmp     eax                     ;do the next block of scans
                   3428: 
                   3429: afscr_done:
                   3430:         PLAIN_RET
                   3431: 
                   3432: page
                   3433: 
                   3434: ;--------------------------Private-Routine------------------------------;
                   3435: ; and_from_save
                   3436: ;
                   3437: ;   The given area of the save buffer is ANDed into the work buffer
                   3438: ;
                   3439: ; Entry:
                   3440: ;       ESI --> RECT_DATA structure to use
                   3441: ;       EGA programmed for AND mode
                   3442: ; Returns:
                   3443: ;       None
                   3444: ; Error Returns:
                   3445: ;       No error return.
                   3446: ; Registers Preserved:
                   3447: ;       EBP
                   3448: ; Registers Destroyed:
                   3449: ;       EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
                   3450: ; Calls:
                   3451: ;       None
                   3452: ;
                   3453: ;-----------------------------------------------------------------------;
                   3454: 
                   3455: ;-----------------------------------------------------------------------;
                   3456: ; This is the key to wrapping in the buffer.  It is a power of two, and
                   3457: ; in this case the entire size is 256 bytes.  If it wasn't 256 bytes, an
                   3458: ; and mask could be used for wrapping.
                   3459: ;-----------------------------------------------------------------------;
                   3460: 
                   3461:         .ERRNZ  SAVE_BUFFER_WIDTH-8
                   3462:         .ERRNZ  SAVE_BUFFER_HEIGHT-32
                   3463:         .ERRNZ  SAVE_BUFFER_WIDTH*SAVE_BUFFER_HEIGHT-256
                   3464: 
                   3465:         align   4
                   3466: and_from_save:
                   3467: 
                   3468:         .ERRNZ  pd_rd
                   3469: 
                   3470: ; See if we'll wrap in X.  If so, split the operation into two parts
                   3471: 
                   3472:         movzx   eax, WORD PTR [esi].rd_ptbWork
                   3473:         movzx   ecx, WORD PTR [esi].rd_ptbSave
                   3474: 
                   3475:         .ERRNZ  ptb_y-ptb_x-1
                   3476: 
                   3477:         movzx   edx, WORD PTR [esi].rd_sizb
                   3478: 
                   3479:         .ERRNZ  sizb_cy-sizb_cx-1
                   3480: 
                   3481:         mov     bl, cl
                   3482:         add     bl, dl
                   3483:         sub     bl, SAVE_BUFFER_WIDTH   ;BL = is overhang
                   3484:         jle     and_from_save_do_last_pass ;No overhang
                   3485: 
                   3486:         sub     dl, bl                  ;Set X extent for pass 1
                   3487:         mov     bh, dl                  ;Need it for pass 2
                   3488:         push    esi                     ;Must keep rectangle pointer around
                   3489:         push    ebx
                   3490:         call    and_from_save_do_a_pass ;Process first half
                   3491:         pop     ebx
                   3492:         pop     esi
                   3493:         movzx   eax, WORD PTR [esi].rd_ptbWork
                   3494:         movzx   ecx, WORD PTR [esi].rd_ptbSave
                   3495: 
                   3496:         .ERRNZ  ptb_y-ptb_x-1
                   3497: 
                   3498:         movzx   edx, WORD PTR [esi].rd_sizb
                   3499: 
                   3500:         .ERRNZ  sizb_cy-sizb_cx-1
                   3501: 
                   3502:         add     al, bh                  ;Move right in work area
                   3503:         mov     dl, bl                  ;Set new extent
                   3504:         xor     cl, cl                  ;X origin in save area is 0
                   3505: 
                   3506: and_from_save_do_last_pass:
                   3507: 
                   3508:         call    and_from_save_do_a_pass
                   3509: 
                   3510:         PLAIN_RET
                   3511: 
                   3512: 
                   3513: ;--------------------------Private-Routine------------------------------;
                   3514: ;  and_from_save
                   3515: ;
                   3516: ; Inner loop subroutine for and_from_save.
                   3517: ;
                   3518: ; Entry:
                   3519: ;       AL = X dest start offset in work area (in bytes)
                   3520: ;       AH = Y dest start offset in work area (in scans)
                   3521: ;       CL = X source start offset in save area (in bytes)
                   3522: ;       CH = Y source start offset in save area (in scans)
                   3523: ;       Upper word of ECX *must* be 0!
                   3524: ;       DL = width to AND (in bytes)
                   3525: ;       DH = height to AND (in scans)
                   3526: ;       EGA programmed for AND mode
                   3527: ; Returns:
                   3528: ;       None
                   3529: ; Error Returns:
                   3530: ;       No error return.
                   3531: ; Registers Preserved:
                   3532: ;       EBP
                   3533: ; Registers Destroyed:
                   3534: ;       EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
                   3535: ; Calls:
                   3536: ;       None
                   3537: ;
                   3538: ;------------------------------------------------------------------------;
                   3539: 
                   3540:         align   4
                   3541: and_from_save_do_a_pass:
                   3542: 
                   3543:         push    ebp                     ;save stack frame pointer
                   3544: 
                   3545:         push    eax
                   3546:         push    ecx
                   3547:         push    edx
                   3548: 
                   3549: ; Map the cursor bank in as both the read window and the write window, because
                   3550: ; both the save and work areas are in the cursor bank. Note that we always know
                   3551: ; that the operation fits in a single bank, which simplifies things
                   3552: ; considerably.
                   3553: 
                   3554:         mov     esi,pdsurf
                   3555:         mov     edx,ulPtrBankScan       ;scan line at end of cursor work bank
                   3556:         cmp     edx,[esi].dsurf_rcl1WindowClip.yTop ;is cursor scan less than
                   3557:                                                      ; current bank?
                   3558:         jl      short afsav_map_ptr_bank             ;yes, map in proper bank
                   3559:         cmp     edx,[esi].dsurf_rcl1WindowClip.yBottom ;cursor scan greater
                   3560:                                                         ; than current bank?
                   3561:         jl      short afsav_ptr_bank_mapped     ;no, proper bank already mapped
                   3562: afsav_map_ptr_bank:
                   3563: 
                   3564: ; Map cursor work bank into source window.
                   3565: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   3566: 
                   3567:         ptrCall <dword ptr [esi].dsurf_pfnBankControl>,<esi,edx,JustifyBottom>
                   3568: 
                   3569: afsav_ptr_bank_mapped:
                   3570: 
                   3571:         pop     edx
                   3572:         pop     ecx
                   3573:         pop     eax
                   3574: 
                   3575: ; Compute the offset within the work area, which is also the offset from
                   3576: ; the start of the AND mask.
                   3577: 
                   3578:         xor     ebx,ebx
                   3579:         xchg    bl,ah
                   3580:         add     eax,ebx                 ;*1 + X
                   3581:         add     ebx,ebx                 ;*2
                   3582:         add     ebx,ebx                 ;*4
                   3583:         add     ebx,eax                 ;*5 + X
                   3584:         mov     edi,pPtrWork
                   3585:         add     edi,ebx                 ;--> destination in work area relative
                   3586:                                         ;    to start of bitmap
                   3587:         mov     esi,[esi].dsurf_pvBitmapStart ;bitmap start virtual address
                   3588:         push    esi                     ;remember bitmap start for calculating
                   3589:                                         ; save area pointer
                   3590:         add     edi,esi                 ;virtual addresss of work area
                   3591:                                         ; destination start
                   3592:         mov     esi,pAndXor
                   3593:         add     esi,ebx                 ;--> AND mask
                   3594:                                         ; Compute the offset within the save
                   3595:                                         ; area. Note that this is relative to
                   3596:                                         ; screen_buf
                   3597:         xor     ebx,ebx
                   3598:         xchg    bl,ch                   ;EBX = ptbSave.ptb_y,
                   3599:                                         ; ECX = ptbSave.ptb_x
                   3600:         lea     ebx,[ebx*8+ecx]         ;EBX = offset in save area
                   3601: 
                   3602:         .ERRNZ  SAVE_BUFFER_WIDTH-8
                   3603: 
                   3604: ; Compute the adjustment to each scanline.
                   3605: 
                   3606:         mov     cl,dl                   ;width in bytes to AND
                   3607:         mov     eax,WORK_WIDTH
                   3608:         sub     eax,ecx                 ;width in bytes to skip from end of one
                   3609:                                         ; mask/work buffer scan to start of
                   3610:                                         ; next
                   3611: 
                   3612: ; Look up the address at which to enter the AND loop.
                   3613: 
                   3614:         mov     ecx,and_from_save_entry_table[ecx*4]
                   3615: 
                   3616: ; Now get things into the correct registers and enter the loop
                   3617: 
                   3618:         pop     ebp                     ;get back bitmap start virtual address
                   3619:         add     ebp,pPtrSave            ;point to the save area
                   3620:         push    ebp                     ;remember save area virtual address
                   3621:         add     ebp,ebx                 ;set correct save buffer address
                   3622:         sub     ebp,esi                 ;want to use [SI][BP]
                   3623:         jmp     ecx                     ;enter following code
                   3624: 
                   3625: ;-----------------------------------------------------------------------;
                   3626: ; Register usage for the loop will be:
                   3627: ;
                   3628: ;       EAX    =  delta to next scan of AND mask and work area
                   3629: ;       EBX    =  offset in save area of scan start
                   3630: ;       ECX    =  loop address
                   3631: ;       DH     =  height in scans
                   3632: ;       ESI    --> AND mask
                   3633: ;       EDI    --> Destination in work area
                   3634: ;       EBP    =  delta from SI to next byte of save buffer
                   3635: ;-----------------------------------------------------------------------;
                   3636: 
                   3637:         align   4
                   3638: and_from_save_width_5:
                   3639:         cmp     al, [ebp][esi]          ;Load latches from screen
                   3640:         movsb                           ;AND to the work area
                   3641: and_from_save_width_4:
                   3642:         cmp     al, [ebp][esi]
                   3643:         movsb
                   3644: and_from_save_width_3:
                   3645:         cmp     al, [ebp][esi]
                   3646:         movsb
                   3647: and_from_save_width_2:
                   3648:         cmp     al, [ebp][esi]
                   3649:         movsb
                   3650: and_from_save_width_1:
                   3651:         cmp     al, [ebp][esi]
                   3652:         movsb
                   3653: and_from_save_width_0:
                   3654: 
                   3655:         .ERRNZ  and_from_save_width_0-and_from_save_width_1-5
                   3656:         .ERRNZ  and_from_save_width_1-and_from_save_width_2-5
                   3657:         .ERRNZ  and_from_save_width_2-and_from_save_width_3-5
                   3658:         .ERRNZ  and_from_save_width_3-and_from_save_width_4-5
                   3659:         .ERRNZ  and_from_save_width_4-and_from_save_width_5-5
                   3660: 
                   3661:         dec     dh
                   3662:         jz      and_from_save_done
                   3663:         add     esi,eax                 ;--> next AND mask
                   3664:         add     edi,eax                 ;--> next work buffer scan
                   3665:         add     bl,SAVE_BUFFER_WIDTH    ;--> compute address of next
                   3666:                                         ;    scan in the work area
                   3667:         pop     ebp                     ;restore save area pointer
                   3668:         push    ebp                     ;push it again, for next time
                   3669:         add     ebp,ebx
                   3670:         sub     ebp,esi                 ;Want to use SI for incrementing
                   3671: 
                   3672:         jmp     ecx
                   3673: 
                   3674: and_from_save_done:
                   3675:         pop     ebp                     ;clear pushed save area pointer
                   3676: 
                   3677:         pop     ebp                     ;restore stack frame pointer
                   3678: 
                   3679:         PLAIN_RET
                   3680: 
                   3681: page
                   3682: 
                   3683: ;--------------------------Private-Routine------------------------------;
                   3684: ; copy_things_around
                   3685: ;
                   3686: ;   Rectangles to be copied from the save area to the screen are
                   3687: ;   processed, followed by the rectangles to be copied from the
                   3688: ;   screen to the save area.
                   3689: ;
                   3690: ; Entry:
                   3691: ;       AL = fbFlush
                   3692: ; Returns:
                   3693: ;       None
                   3694: ; Error Returns:
                   3695: ;       No error return.
                   3696: ; Registers Preserved:
                   3697: ;       BP
                   3698: ; Registers Destroyed:
                   3699: ;       AX,BX,CX,DX,SI,DI,BP,FLAGS
                   3700: ; Calls:
                   3701: ;       copy_save_to_screen
                   3702: ;       copy_screen_to_save
                   3703: ;
                   3704: ;-----------------------------------------------------------------------;
                   3705: 
                   3706:         align   4
                   3707: copy_things_around:
                   3708: 
                   3709: ;-----------------------------------------------------------------------;
                   3710: ; Program the EGA for COPY mode.  This will be done using M_PROC_WRITE,
                   3711: ; M_DATA_READ, DR_???, and setting GRAF_BIT_MASK to 00.  All but setting
                   3712: ; GRAF_BIT_MASK was done by save_hw_regs.  All planes were also enabled
                   3713: ; for writing by save_hw_regs.
                   3714: ;-----------------------------------------------------------------------;
                   3715: 
                   3716:         mov     ecx, eax
                   3717:         mov     dx, EGA_BASE + GRAF_ADDR
                   3718:         mov     ax, GRAF_BIT_MASK
                   3719:         out     dx, ax                  ;Disable all bits
                   3720:         mov     eax, ecx
                   3721: 
                   3722: ;-----------------------------------------------------------------------;
                   3723: ; Process any copying from the save area to the screen.  If FB_OLD_PTR
                   3724: ; is set, then there cannot be a FB_FLUSH_X or FB_FLUSH_Y.
                   3725: ;-----------------------------------------------------------------------;
                   3726: 
                   3727:         mov     esi, ppdOld
                   3728:         test    al, FB_OLD_PTR
                   3729:         jnz     cta_copy_from_save      ;The old rectangle goes
                   3730:         test    al, FB_FLUSH_X
                   3731:         jz      @F
                   3732:         mov     esi, offset FLAT:rdFlushX
                   3733:         call    copy_save_to_screen
                   3734:         mov     al, fbFlush
                   3735: @@:
                   3736:         test    al, FB_FLUSH_Y
                   3737:         jz      @F
                   3738:         mov     esi, offset FLAT:rdFlushY
                   3739: cta_copy_from_save:
                   3740:         call    copy_save_to_screen
                   3741: @@:
                   3742: 
                   3743: ;-----------------------------------------------------------------------;
                   3744: ; Process any copying from the screen to the save area.  If FB_NEW_PTR
                   3745: ; or FB_WORK_RECT is set, then there can't be a FB_FLUSH_X or FB_FLUSH_Y
                   3746: ;-----------------------------------------------------------------------;
                   3747: 
                   3748:         mov     al, fbAndRead
                   3749:         mov     esi, ppdNew
                   3750:         test    al, FB_NEW_PTR
                   3751:         jnz     cta_copy_to_save
                   3752:         mov     esi, offset FLAT:rdWork
                   3753:         test    al, FB_WORK_RECT
                   3754:         jnz     cta_copy_to_save
                   3755: 
                   3756: ; Some combination of FB_READ_X, FB_READ_Y
                   3757: 
                   3758:         test    al, FB_READ_X
                   3759:         jz      @F
                   3760:         mov     esi, offset FLAT:rdReadX
                   3761:         call    copy_screen_to_save
                   3762:         mov     al, fbAndRead
                   3763: @@:
                   3764:         test    al, FB_READ_Y
                   3765:         jz      @F
                   3766:         mov     esi, offset FLAT:rdReadY
                   3767: cta_copy_to_save:
                   3768:         call    copy_screen_to_save
                   3769: @@:
                   3770:         PLAIN_RET
                   3771: 
                   3772: page
                   3773: 
                   3774: ;--------------------------Private-Routine------------------------------;
                   3775: ; copy_save_to_screen
                   3776: ;
                   3777: ;   The given rectangle is copied from the save area to the screen
                   3778: ;
                   3779: ; Entry:
                   3780: ;       ESI --> RECT_DATA structure to use
                   3781: ;       EGA programmed for COPY mode
                   3782: ; Returns:
                   3783: ;       None
                   3784: ; Error Returns:
                   3785: ;       No error return.
                   3786: ; Registers Preserved:
                   3787: ;       EBP
                   3788: ; Registers Destroyed:
                   3789: ;       EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
                   3790: ; Calls:
                   3791: ;       None
                   3792: ;
                   3793: ;-----------------------------------------------------------------------;
                   3794: 
                   3795: ;-----------------------------------------------------------------------;
                   3796: ; This is the key to wrapping in the buffer.  It is a power of two, and
                   3797: ; in this case the entire size is 256 bytes.  If it wasn't 256 bytes, an
                   3798: ; and mask could be used for wrapping.
                   3799: ;-----------------------------------------------------------------------;
                   3800: 
                   3801:         .ERRNZ  SAVE_BUFFER_WIDTH-8
                   3802:         .ERRNZ  SAVE_BUFFER_HEIGHT-32
                   3803:         .ERRNZ  SAVE_BUFFER_WIDTH*SAVE_BUFFER_HEIGHT-256
                   3804: 
                   3805:         align   4
                   3806: copy_save_to_screen:
                   3807: 
                   3808:         .ERRNZ  pd_rd
                   3809: 
                   3810: ; Map the proper bank into the destination window for the top destination
                   3811: ; scan line.
                   3812: 
                   3813:         mov     ebx,pdsurf
                   3814:         mov     edx,[esi].rd_ptlScreen.ptl_y
                   3815:         mov     ulCurrentTopScan,edx    ;remember where the top dest scan is
                   3816:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is copy top less than
                   3817:                                                      ; current dest bank?
                   3818:         jl      short sts_map_init_bank              ;yes, map in proper bank
                   3819:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;copy top greater than
                   3820:                                                         ; current dest bank?
                   3821:         jl      short sts_init_bank_mapped      ;no, proper bank already mapped
                   3822: sts_map_init_bank:
                   3823: 
                   3824: ; Map bank containing the top destination (screen) scan line into dest window.
                   3825: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   3826: 
                   3827:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
                   3828:                 <ebx,edx,JustifyTop,MapDestBank>
                   3829: 
                   3830: sts_init_bank_mapped:
                   3831: 
                   3832: 
                   3833: ; Map the cursor bank into the source window.
                   3834: 
                   3835:         mov     edx,ulPtrBankScan       ;scan line at end of cursor work bank
                   3836:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is cursor scan less than
                   3837:                                                      ; current source bank?
                   3838:         jl      short sts_map_ptr_bank              ;yes, map in proper bank
                   3839:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;cursor scan greater
                   3840:                                                         ; than current source
                   3841:                                                         ; bank?
                   3842:         jl      short sts_ptr_bank_mapped       ;no, proper bank already mapped
                   3843: sts_map_ptr_bank:
                   3844: 
                   3845: ; Map cursor work bank into source window.
                   3846: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   3847: 
                   3848:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
                   3849:                 <ebx,edx,JustifyBottom,MapSourceBank>
                   3850: 
                   3851: sts_ptr_bank_mapped:
                   3852: 
                   3853: 
                   3854: ; Compute the virtual address of the save area.
                   3855: 
                   3856:         mov     eax,pPtrSave
                   3857:         add     eax,[ebx].dsurf_pvBitmapStart2WindowS ;save area virtual addr
                   3858:         mov     pSaveAddr,eax
                   3859: 
                   3860: ; Compute the screen address and delta to next scan of the screen.
                   3861: 
                   3862:         mov     edi,lNextScan
                   3863:         imul    edi,[esi].rd_ptlScreen.ptl_y
                   3864:         add     edi,[esi].rd_ptlScreen.ptl_x ;start dest offset in bitmap
                   3865:         add     edi,[ebx].dsurf_pvBitmapStart2WindowD ;start dest virtual addr
                   3866:         movzx   edx,WORD PTR [esi].rd_sizb
                   3867: 
                   3868:         .ERRNZ  sizb_cy-sizb_cx-1
                   3869: 
                   3870: ; Calculate the number of scans we'll do in this bank.
                   3871: 
                   3872:         mov     ecx,[ebx].dsurf_rcl2WindowClipD.yBottom
                   3873:         sub     ecx,ulCurrentTopScan    ;max # of scans that can be handled in
                   3874:                                         ; the initial bank
                   3875:         sub     eax,eax
                   3876:         mov     al,dh                   ;total # of scans to copy
                   3877:         cmp     eax,ecx                 ;can we handle all remaining scans in
                   3878:                                         ; this bank?
                   3879:         jb      short @F                ;yes
                   3880:         mov     eax,ecx                 ;no, so we'll do the whole bank's worth
                   3881: @@:
                   3882:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   3883:         sub     dh,al                   ;count this bank's scans off total
                   3884:         mov     byte ptr cjTotalScans,dh ;remember # of scans after this bank
                   3885:         mov     dh,al                   ;# of scans to do in this bank
                   3886: 
                   3887: ; Calculate the offset from the end of one dest scan line to the next.
                   3888: 
                   3889:         mov     al,dl           ;width to copy in bytes
                   3890:         neg     eax
                   3891:         add     eax,lNextScan   ;offset from end of one dest scan to start of
                   3892:                                 ; next
                   3893: 
                   3894: ; Compute the save area offset.
                   3895: 
                   3896:         movzx   ecx,WORD PTR [esi].rd_ptbSave
                   3897: 
                   3898:         .ERRNZ  ptb_y-ptb_x-1
                   3899: 
                   3900:         xor     ebx,ebx
                   3901:         xchg    bl,ch
                   3902:         lea     ebx,[ebx*8+ecx]
                   3903: 
                   3904:         .ERRNZ  SAVE_BUFFER_WIDTH-8
                   3905: 
                   3906: ; Determine if any wrap will occur, and handle it if so.
                   3907: 
                   3908:         add     cl,dl                   ;add extent (DL) to start X (CL)
                   3909:         sub     cl,SAVE_BUFFER_WIDTH
                   3910:         jg      short save_to_screen_wraps    ;CL = amount of wrap
                   3911: 
                   3912: ;-----------------------------------------------------------------------;
                   3913: ; The copy will not wrap, so we can get into some tighter code for it.
                   3914: ;
                   3915: ; Currently:
                   3916: ;       EAX    =  delta to next destination scan
                   3917: ;       EBX    =  offset into the save buffer
                   3918: ;       DL     =  width of copy
                   3919: ;       DH     =  height of copy
                   3920: ;       EDI    --> destination
                   3921: ;-----------------------------------------------------------------------;
                   3922: 
                   3923: copy_save_next_scan:
                   3924:         sub     ecx,ecx                 ;prepare for loading CL in loop
                   3925:         push    ebp                     ;preserve stack frame pointer
                   3926:         mov     ebp,pSaveAddr
                   3927: copy_save_next_scan_loop:
                   3928:         lea     esi,[ebp+ebx]
                   3929:         mov     cl,dl
                   3930:         rep     movsb
                   3931:         add     bl,SAVE_BUFFER_WIDTH
                   3932:         add     edi,eax
                   3933:         dec     dh
                   3934:         jnz     copy_save_next_scan_loop
                   3935: 
                   3936:         pop     ebp                     ;restore stack frame pointer
                   3937:         cmp     byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
                   3938:         jz      short sts_done          ;no, we're done
                   3939:                                         ;advance to next dest bank and continue
                   3940:                                         ; copying
                   3941:         push    eax                     ;preserve dest next scan
                   3942:         push    edx                     ;preserve width of copy
                   3943:         mov     esi,pdsurf
                   3944:         sub     edi,[esi].dsurf_pvBitmapStart2WindowD
                   3945:                                         ;calculate the destination offset
                   3946:                                         ; within the bitmap, because the start
                   3947:                                         ; address is about to move
                   3948:         mov     edx,ulCurrentTopScan
                   3949: 
                   3950: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   3951: 
                   3952:         ptrCall <dword ptr [esi].dsurf_pfnBankControl2Window>, \
                   3953:                 <esi,edx,JustifyTop,MapDestBank> ;map in the next dest bank
                   3954: 
                   3955:         add     edi,[esi].dsurf_pvBitmapStart2WindowD
                   3956:                                         ;add back in the bitmap start address
                   3957:                                         ; to yield the virtual dest address
                   3958:         mov     edx,[esi].dsurf_rcl2WindowClipD.yBottom
                   3959:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   3960:                                         ; the new bank
                   3961:         sub     eax,eax
                   3962:         mov     al,byte ptr cjTotalScans ;remaining scan count
                   3963:         cmp     eax,edx                 ;can we handle all remaining scans in
                   3964:                                         ; this bank?
                   3965:         jb      short @F                ;yes
                   3966:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   3967: @@:
                   3968:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   3969:         sub     byte ptr cjTotalScans,al ;count this bank's scans off total
                   3970:         pop     edx                     ;restore copy width in DL
                   3971:         mov     dh,al                   ;# of scans to do in this bank
                   3972:         pop     eax                     ;restore dest next scan
                   3973:         jmp     copy_save_next_scan     ;do the next block of scans
                   3974: 
                   3975: sts_done:
                   3976:         PLAIN_RET
                   3977: 
                   3978: ;-----------------------------------------------------------------------;
                   3979: ; The copy will wrap, so we have to handle it as two copies
                   3980: ;
                   3981: ; Currently:
                   3982: ;       EDI    --> destination
                   3983: ;       EAX    =  delta to next destination scan
                   3984: ;       DL     =  width of copy
                   3985: ;       DH     =  height of copy
                   3986: ;       EBX    =  offset into the save buffer
                   3987: ;       CL     =  amount of overflow
                   3988: ;-----------------------------------------------------------------------;
                   3989: 
                   3990:         align   4
                   3991: save_to_screen_wraps:
                   3992:         sub     dl,cl                   ;set extent of first copy
                   3993:         mov     byte ptr jPostWrapWidth,cl ;set extent of second copy
                   3994:         sub     ecx,ecx                 ;prepare for loading CL in loop
                   3995: 
                   3996: copy_save_next_scan_wrap_loop:
                   3997:         mov     esi,pSaveAddr
                   3998:         add     esi,ebx
                   3999:         mov     cl,dl
                   4000:         rep     movsb
                   4001:         sub     esi,SAVE_BUFFER_WIDTH
                   4002:         mov     cl,byte ptr jPostWrapWidth
                   4003:         rep     movsb
                   4004:         add     bl,SAVE_BUFFER_WIDTH
                   4005:         add     edi,eax
                   4006:         dec     dh
                   4007:         jnz     copy_save_next_scan_wrap_loop
                   4008: 
                   4009:         cmp     byte ptr cjTotalScans,0 ;more lines (in next dest bank)?
                   4010:         jz      short sts_done          ;no, we're done
                   4011:                                         ;advance to next dest bank and continue
                   4012:                                         ; copying
                   4013:         push    eax                     ;preserve dest next scan
                   4014:         push    edx                     ;preserve width of copy
                   4015:         mov     esi,pdsurf
                   4016:         sub     edi,[esi].dsurf_pvBitmapStart2WindowD
                   4017:                                         ;calculate the destination offset
                   4018:                                         ; within the bitmap, because the start
                   4019:                                         ; address is about to move
                   4020:         mov     edx,ulCurrentTopScan
                   4021: 
                   4022: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   4023: 
                   4024:         ptrCall <dword ptr [esi].dsurf_pfnBankControl2Window>, \
                   4025:                 <esi,edx,JustifyTop,MapDestBank> ;map in the next dest bank
                   4026: 
                   4027:         add     edi,[esi].dsurf_pvBitmapStart2WindowD
                   4028:                                         ;add back in the bitmap start address
                   4029:                                         ; to yield the virtual dest address
                   4030:         mov     edx,[esi].dsurf_rcl2WindowClipD.yBottom
                   4031:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   4032:                                         ; the new bank
                   4033:         sub     eax,eax
                   4034:         mov     al,byte ptr cjTotalScans ;remaining scan count
                   4035:         cmp     eax,edx                 ;can we handle all remaining scans in
                   4036:                                         ; this bank?
                   4037:         jb      short @F                ;yes
                   4038:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   4039: @@:
                   4040:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   4041:         sub     byte ptr cjTotalScans,al ;count this bank's scans off total
                   4042:         pop     edx                     ;restore copy width in DL
                   4043:         mov     dh,al                   ;# of scans to do in this bank
                   4044:         pop     eax                     ;restore dest next scan
                   4045:         sub     ecx,ecx                 ;prepare for loading CL in loop
                   4046:         jmp     copy_save_next_scan_wrap_loop ;do the next block of scans
                   4047: 
                   4048: page
                   4049: 
                   4050: ;--------------------------Private-Routine------------------------------;
                   4051: ; copy_screen_to_save
                   4052: ;
                   4053: ;   The given rectangle is copied from the screen to the save area
                   4054: ;
                   4055: ; Entry:
                   4056: ;       ESI --> RECT_DATA structure to use
                   4057: ;       EGA programmed for COPY mode
                   4058: ; Returns:
                   4059: ;       None
                   4060: ; Error Returns:
                   4061: ;       No error return.
                   4062: ; Registers Preserved:
                   4063: ;       EBP
                   4064: ; Registers Destroyed:
                   4065: ;       EAX,EBX,ECX,EDX,ESI,EDI,EFLAGS
                   4066: ; Calls:
                   4067: ;       None
                   4068: ;
                   4069: ;-----------------------------------------------------------------------;
                   4070: 
                   4071: 
                   4072: ;-----------------------------------------------------------------------;
                   4073: ; This is the key to wrapping in the buffer.  It is a power of two, and
                   4074: ; in this case the entire size is 256 bytes.  If it wasn't 256 bytes, an
                   4075: ; and mask could be used for wrapping.
                   4076: ;-----------------------------------------------------------------------;
                   4077: 
                   4078:         .ERRNZ  SAVE_BUFFER_WIDTH-8
                   4079:         .ERRNZ  SAVE_BUFFER_HEIGHT-32
                   4080:         .ERRNZ  SAVE_BUFFER_WIDTH*SAVE_BUFFER_HEIGHT-256
                   4081: 
                   4082:         align   4
                   4083: copy_screen_to_save:
                   4084: 
                   4085:         .ERRNZ  pd_rd
                   4086: 
                   4087: ; Map the proper bank into the source window for the top source scan line.
                   4088: 
                   4089:         mov     ebx,pdsurf
                   4090:         mov     edx,[esi].rd_ptlScreen.ptl_y
                   4091:         mov     ulCurrentTopScan,edx    ;remember where the top source scan is
                   4092:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yTop ;is copy top less than
                   4093:                                                      ; current source bank?
                   4094:         jl      short scrts_map_init_bank            ;yes, map in proper bank
                   4095:         cmp     edx,[ebx].dsurf_rcl2WindowClipS.yBottom ;copy top greater than
                   4096:                                                         ; current source bank?
                   4097:         jl      short scrts_init_bank_mapped    ;no, proper bank already mapped
                   4098: scrts_map_init_bank:
                   4099: 
                   4100: ; Map bank containing the top source (screen) scan line into source window.
                   4101: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   4102: 
                   4103:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
                   4104:                 <ebx,edx,JustifyTop,MapSourceBank>
                   4105: 
                   4106: scrts_init_bank_mapped:
                   4107: 
                   4108: 
                   4109: ; Map the cursor bank into the dest window.
                   4110: 
                   4111:         mov     edx,ulPtrBankScan       ;scan line at end of cursor work bank
                   4112:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yTop ;is cursor scan less than
                   4113:                                                      ; current dest bank?
                   4114:         jl      short scrts_map_ptr_bank            ;yes, map in proper bank
                   4115:         cmp     edx,[ebx].dsurf_rcl2WindowClipD.yBottom ;cursor scan greater
                   4116:                                                         ; than current dest
                   4117:                                                         ; bank?
                   4118:         jl      short scrts_ptr_bank_mapped     ;no, proper bank already mapped
                   4119: scrts_map_ptr_bank:
                   4120: 
                   4121: ; Map cursor work bank into dest window.
                   4122: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   4123: 
                   4124:         ptrCall <dword ptr [ebx].dsurf_pfnBankControl2Window>, \
                   4125:                 <ebx,edx,JustifyBottom,MapDestBank>
                   4126: 
                   4127: scrts_ptr_bank_mapped:
                   4128: 
                   4129: 
                   4130: ; Compute the virtual address of the save area.
                   4131: 
                   4132:         mov     eax,pPtrSave
                   4133:         add     eax,[ebx].dsurf_pvBitmapStart2WindowD ;save area virtual addr
                   4134:         mov     pSaveAddr,eax
                   4135: 
                   4136: ; Compute the source screen address and delta to next scan of the screen.
                   4137: 
                   4138:         mov     edi,lNextScan
                   4139:         imul    edi,[esi].rd_ptlScreen.ptl_y
                   4140:         add     edi,[esi].rd_ptlScreen.ptl_x ;start source offset in bitmap
                   4141:         add     edi,[ebx].dsurf_pvBitmapStart2WindowS ;start source virtual
                   4142:                                                       ; address
                   4143:         movzx   edx,WORD PTR [esi].rd_sizb
                   4144: 
                   4145:         .ERRNZ  sizb_cy-sizb_cx-1
                   4146: 
                   4147: ; Calculate the number of scans we'll do in this bank.
                   4148: 
                   4149:         mov     ecx,[ebx].dsurf_rcl2WindowClipS.yBottom
                   4150:         sub     ecx,ulCurrentTopScan    ;max # of scans that can be handled in
                   4151:                                         ; the initial bank
                   4152:         sub     eax,eax
                   4153:         mov     al,dh                   ;total # of scans to copy
                   4154:         cmp     eax,ecx                 ;can we handle all remaining scans in
                   4155:                                         ; this bank?
                   4156:         jb      short @F                ;yes
                   4157:         mov     eax,ecx                 ;no, so we'll do the whole bank's worth
                   4158: @@:
                   4159:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   4160:         sub     dh,al                   ;count this bank's scans off total
                   4161:         mov     byte ptr cjTotalScans,dh ;remember # of scans after this bank
                   4162:         mov     dh,al                   ;# of scans to do in this bank
                   4163: 
                   4164: ; Calculate the offset from the end of one source scan line to the next.
                   4165: 
                   4166:         mov     al,dl           ;width to copy in bytes
                   4167:         neg     eax
                   4168:         add     eax,lNextScan   ;offset from end of one source scan to start of
                   4169:                                 ; next
                   4170: 
                   4171: ; Compute the save area offset.
                   4172: 
                   4173:         movzx   ecx,WORD PTR [esi].rd_ptbSave
                   4174: 
                   4175:         .ERRNZ  ptb_y-ptb_x-1
                   4176: 
                   4177:         xor     ebx,ebx
                   4178:         xchg    bl,ch
                   4179:         lea     ebx,[ebx*8+ecx]
                   4180: 
                   4181:         .ERRNZ  SAVE_BUFFER_WIDTH-8
                   4182: 
                   4183:         mov     esi,edi                 ;ESI -> initial source byte
                   4184: 
                   4185: ; Determine if any wrap will occur, and handle it if so.
                   4186: 
                   4187:         add     cl,dl                   ;add extent (DL) to start X (CL)
                   4188:         sub     cl,SAVE_BUFFER_WIDTH
                   4189:         jg      short screen_to_save_wraps    ;CL = amount of wrap
                   4190: 
                   4191: ;-----------------------------------------------------------------------;
                   4192: ; The copy will not wrap, so we can get into some tighter code for it.
                   4193: ;
                   4194: ; Currently:
                   4195: ;       EAX    =  delta to next source scan
                   4196: ;       EBX    =  offset into the save buffer
                   4197: ;       DL     =  width of copy
                   4198: ;       DH     =  height of copy
                   4199: ;       ESI    --> source
                   4200: ;-----------------------------------------------------------------------;
                   4201: 
                   4202: copy_screen_next_scan:
                   4203:         sub     ecx,ecx                 ;prepare for loading CL in loop
                   4204:         push    ebp                     ;preserve stack frame pointer
                   4205:         mov     ebp,pSaveAddr
                   4206: copy_screen_next_scan_loop:
                   4207:         lea     edi,[ebp+ebx]
                   4208:         mov     cl,dl
                   4209:         rep     movsb
                   4210:         add     bl,SAVE_BUFFER_WIDTH
                   4211:         add     esi,eax
                   4212:         dec     dh
                   4213:         jnz     copy_screen_next_scan_loop
                   4214: 
                   4215:         pop     ebp                     ;restore stack frame pointer
                   4216:         cmp     byte ptr cjTotalScans,0 ;more lines (in next source bank)?
                   4217:         jz      short scrts_done        ;no, we're done
                   4218:                                         ;advance to next source bank and
                   4219:                                         ; continue copying
                   4220:         push    eax                     ;preserve source next scan
                   4221:         push    edx                     ;preserve width of copy
                   4222:         mov     edi,pdsurf
                   4223:         sub     esi,[edi].dsurf_pvBitmapStart2WindowS
                   4224:                                         ;calculate the source offset
                   4225:                                         ; within the bitmap, because the start
                   4226:                                         ; address is about to move
                   4227:         mov     edx,ulCurrentTopScan
                   4228: 
                   4229: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   4230: 
                   4231:         ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
                   4232:                 <edi,edx,JustifyTop,MapSourceBank> ;map in the next source bank
                   4233: 
                   4234:         add     esi,[edi].dsurf_pvBitmapStart2WindowS
                   4235:                                         ;add back in the bitmap start address
                   4236:                                         ; to yield the virtual source address
                   4237:         mov     edx,[edi].dsurf_rcl2WindowClipS.yBottom
                   4238:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   4239:                                         ; the new bank
                   4240:         sub     eax,eax
                   4241:         mov     al,byte ptr cjTotalScans ;remaining scan count
                   4242:         cmp     eax,edx                 ;can we handle all remaining scans in
                   4243:                                         ; this bank?
                   4244:         jb      short @F                ;yes
                   4245:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   4246: @@:
                   4247:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   4248:         sub     byte ptr cjTotalScans,al ;count this bank's scans off total
                   4249:         pop     edx                     ;restore copy width in DL
                   4250:         mov     dh,al                   ;# of scans to do in this bank
                   4251:         pop     eax                     ;restore source next scan
                   4252:         jmp     copy_screen_next_scan   ;do the next block of scans
                   4253: 
                   4254: scrts_done:
                   4255:         PLAIN_RET
                   4256: 
                   4257: ;-----------------------------------------------------------------------;
                   4258: ; The copy will wrap, so we have to handle it as two copies
                   4259: ;
                   4260: ; Currently:
                   4261: ;       EAX    =  delta to next source scan
                   4262: ;       EBX    =  offset into the save buffer
                   4263: ;       CL     =  amount of overflow
                   4264: ;       DL     =  width of copy
                   4265: ;       DH     =  height of copy
                   4266: ;       ESI    --> source
                   4267: ;-----------------------------------------------------------------------;
                   4268: 
                   4269:         align   4
                   4270: screen_to_save_wraps:
                   4271:         sub     dl,cl                   ;set extent of first copy
                   4272:         mov     byte ptr jPostWrapWidth,cl ;set extent of second copy
                   4273:         sub     ecx,ecx                 ;prepare for loading CL in loop
                   4274: 
                   4275: copy_screen_next_scan_wrap_loop:
                   4276:         mov     edi,pSaveAddr
                   4277:         add     edi,ebx
                   4278:         mov     cl,dl
                   4279:         rep     movsb
                   4280:         sub     edi,SAVE_BUFFER_WIDTH
                   4281:         mov     cl,byte ptr jPostWrapWidth
                   4282:         rep     movsb
                   4283:         add     bl,SAVE_BUFFER_WIDTH
                   4284:         add     esi,eax
                   4285:         dec     dh
                   4286:         jnz     copy_screen_next_scan_wrap_loop
                   4287: 
                   4288:         cmp     byte ptr cjTotalScans,0 ;more lines (in next source bank)?
                   4289:         jz      short scrts_done          ;no, we're done
                   4290:                                         ;advance to next source bank and
                   4291:                                         ; continue copying
                   4292:         push    eax                     ;preserve source next scan
                   4293:         push    edx                     ;preserve width of copy
                   4294:         mov     edi,pdsurf
                   4295:         sub     esi,[edi].dsurf_pvBitmapStart2WindowS
                   4296:                                         ;calculate the source offset
                   4297:                                         ; within the bitmap, because the start
                   4298:                                         ; address is about to move
                   4299:         mov     edx,ulCurrentTopScan
                   4300: 
                   4301: ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
                   4302: 
                   4303:         ptrCall <dword ptr [edi].dsurf_pfnBankControl2Window>, \
                   4304:                 <edi,edx,JustifyTop,MapSourceBank> ;map in the next source bank
                   4305: 
                   4306:         add     esi,[edi].dsurf_pvBitmapStart2WindowS
                   4307:                                         ;add back in the bitmap start address
                   4308:                                         ; to yield the virtual source address
                   4309:         mov     edx,[edi].dsurf_rcl2WindowClipS.yBottom
                   4310:         sub     edx,ulCurrentTopScan    ;max # of scans that can be handled in
                   4311:                                         ; the new bank
                   4312:         sub     eax,eax
                   4313:         mov     al,byte ptr cjTotalScans ;remaining scan count
                   4314:         cmp     eax,edx                 ;can we handle all remaining scans in
                   4315:                                         ; this bank?
                   4316:         jb      short @F                ;yes
                   4317:         mov     eax,edx                 ;no, so we'll do the whole bank's worth
                   4318: @@:
                   4319:         add     ulCurrentTopScan,eax    ;set top scan for next bank
                   4320:         sub     byte ptr cjTotalScans,al ;count this bank's scans off total
                   4321:         pop     edx                     ;restore copy width in DL
                   4322:         mov     dh,al                   ;# of scans to do in this bank
                   4323:         pop     eax                     ;restore source next scan
                   4324:         sub     ecx,ecx                 ;prepare for loading CL in loop
                   4325:         jmp     copy_screen_next_scan_wrap_loop ;do the next block of scans
                   4326: 
                   4327: endProc vDrawPointer
                   4328: 
                   4329: ;-----------------------------------------------------------------------;
                   4330: ; vDIB4Convert*
                   4331: ;
                   4332: ; Converts the specified number of source 4 bpp bits into the
                   4333: ; buffer.  These are support routines for vDIB4Planer, where a
                   4334: ; source byte converts into two aligned bits
                   4335: ;
                   4336: ; Entry:
                   4337: ;   EAX 31:8 = 0
                   4338: ;   EBP --> Bit conversion table
                   4339: ;   ESI --> Source bitmap
                   4340: ;   EDI --> Planer destination
                   4341: ;   ECX  =  Loop count
                   4342: ; Exit:
                   4343: ;   EBP --> Bit conversion table
                   4344: ;   ESI --> Next source byte
                   4345: ;   EDI --> Next planer destination
                   4346: ;   EDX  =  Last planer byte accumulated
                   4347: ; Registers Destroyed:
                   4348: ;   EAX,ECX,EDX
                   4349: ; Registers Preserved:
                   4350: ;-----------------------------------------------------------------------;
                   4351:         extrn   aulDefBitMapping:dword
                   4352: 
                   4353:         align   4
                   4354: vDIB4Convert8   proc
                   4355:         lodsb
                   4356:         mov     ebx,eax
                   4357:         shr     eax,4
                   4358:         and     ebx,00001111b
                   4359:         mov     edx,[ebp][eax*4]
                   4360:         shl     edx,1
                   4361:         or      edx,[ebp][ebx*4]
                   4362: vDIB4Convert6:
                   4363:         lodsb
                   4364:         shl     edx,1
                   4365:         mov     ebx,eax
                   4366:         shr     eax,4
                   4367:         and     ebx,00001111b
                   4368:         or      edx,[ebp][eax*4]
                   4369:         shl     edx,1
                   4370:         or      edx,[ebp][ebx*4]
                   4371: vDIB4Convert4:
                   4372:         lodsb
                   4373:         shl     edx,1
                   4374:         mov     ebx,eax
                   4375:         shr     eax,4
                   4376:         and     ebx,00001111b
                   4377:         or      edx,[ebp][eax*4]
                   4378:         shl     edx,1
                   4379:         or      edx,[ebp][ebx*4]
                   4380: vDIB4Convert2:
                   4381:         lodsb
                   4382:         shl     edx,1
                   4383:         mov     ebx,eax
                   4384:         shr     eax,4
                   4385:         and     ebx,00001111b
                   4386:         or      edx,[ebp][eax*4]
                   4387:         shl     edx,1
                   4388:         or      edx,[ebp][ebx*4]
                   4389:         mov     [edi][4*0],dl
                   4390:         mov     [edi][4*1],dh
                   4391:         ror     edx,16
                   4392:         mov     [edi][4*2],dl
                   4393:         mov     [edi][4*3],dh
                   4394:         inc     edi
                   4395:         dec     ecx
                   4396:         jnz     vDIB4Convert8
                   4397:         ret
                   4398: 
                   4399: vDIB4Convert8   endp
                   4400: 
                   4401: page
                   4402: ;-----------------------------------------------------------------------;
                   4403: ; vConvertDIBPointer
                   4404: ;
                   4405: ; Converts the passed DIB into a planer format, then synthesizes the
                   4406: ; XOR mask.
                   4407: ;
                   4408: ; Entry:
                   4409: ;   ESI --> Color Bits, 4bpp format
                   4410: ;   EDI --> Planer destination
                   4411: ;   ECX  =  Bitmap height
                   4412: ;   EBP  =  pulXlate for color mapping
                   4413: ;    DX  = wFlags
                   4414: ; Exit:
                   4415: ;   None
                   4416: ; Registers Destroyed:
                   4417: ;   EAX,EBX,ECX,EDX,ESI,EDI,Flags
                   4418: ; Registers Preserved:
                   4419: ;-----------------------------------------------------------------------;
                   4420: 
                   4421:         align   4
                   4422: vConvertDIBPointer  proc
                   4423: 
                   4424: ; Convert the scans as necessary into planer format.  We'll assume a fixed
                   4425: ; size of 32 bits wide
                   4426: 
                   4427:         push    edx                         ;Save
                   4428:         push    edi
                   4429: @@:
                   4430:         push    ecx                         ;Save loop count
                   4431:         push    edi                         ;Save destination pointer
                   4432:         push    esi                         ;Save source pointer
                   4433:         mov     ecx,PTR_WIDTH
                   4434:         xor     eax,eax                     ;Needs to be zero initialized
                   4435:         call    vDIB4Convert8               ;Convert one scan
                   4436:         pop     esi
                   4437:         pop     edi
                   4438:         pop     ecx
                   4439:         add     edi,16                      ;--> next destination scan
                   4440:         add     esi,16                      ;--> next source scan
                   4441:         dec     ecx
                   4442:         jnz     @B
                   4443: 
                   4444: ; The bitmap has been converted into planer format.  If it needs flipping,
                   4445: ; then flip it
                   4446: 
                   4447:         pop     esi                         ;Start of plane 0
                   4448:         pop     edx
                   4449:         or      dl,dl
                   4450:         js      skipping_first_invert       ;Color bitmap is TOPDOWN
                   4451:         mov     ecx,PTR_HEIGHT / 2          ;* scans to flip
                   4452:         lea     edi,[esi][PTR_HEIGHT*4*4]   ;--> last scan
                   4453: 
                   4454: flip_next_scan:
                   4455:         sub     edi,16                  ;decrement target pointer
                   4456: 
                   4457:         mov     eax,[esi][00h]          ;Load
                   4458:         xchg    [edi][00h],eax          ;Swap
                   4459:         mov     [esi][00h],eax          ;Save
                   4460: 
                   4461:         mov     eax,[esi][04h]          ;Load
                   4462:         xchg    [edi][04h],eax          ;Swap
                   4463:         mov     [esi][04h],eax          ;Save
                   4464: 
                   4465:         mov     eax,[esi][08h]          ;Load
                   4466:         xchg    [edi][08h],eax          ;Swap
                   4467:         mov     [esi][08h],eax          ;Save
                   4468: 
                   4469:         mov     eax,[esi][0Ch]          ;Load
                   4470:         xchg    [edi][0Ch],eax          ;Swap
                   4471:         mov     [esi][0Ch],eax          ;Save
                   4472: 
                   4473:         add     esi,16                  ;increment source pointer
                   4474:         loop    flip_next_scan
                   4475: 
                   4476: skipping_first_invert:
                   4477:         ret
                   4478: 
                   4479: vConvertDIBPointer  endp
                   4480: 
                   4481: _TEXT$01   ends
                   4482: 
                   4483:         end
                   4484: 

unix.superglobalmegacorp.com

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