|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.