Annotation of ntddk/src/video/displays/vga/i386/pointer.asm, revision 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.