]> 4ch.mooo.com Git - 16.git/blob - 16/xlib/xrect.asm
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / 16 / xlib / xrect.asm
1 ;-----------------------------------------------------------------------\r
2 ; MODULE XRECT\r
3 ;\r
4 ; Rectangle functions all MODE X 256 Color resolutions\r
5 ;\r
6 ; Compile with Tasm.\r
7 ; C callable.\r
8 ;\r
9 ;\r
10 ; ****** XLIB - Mode X graphics library                ****************\r
11 ; ******                                               ****************\r
12 ; ****** Written By Themie Gouthas                     ****************\r
13 ;\r
14 ; egg@dstos3.dsto.gov.au\r
15 ; teg@bart.dsto.gov.au\r
16 ;-----------------------------------------------------------------------\r
17 \r
18 \r
19 include xlib.inc\r
20 include xrect.inc\r
21 \r
22 \r
23         .data\r
24 ; Plane masks for clipping left and right edges of rectangle.\r
25         LeftClipPlaneMask       db      00fh,00eh,00ch,008h\r
26         RightClipPlaneMask      db      00fh,001h,003h,007h\r
27         .code\r
28 \r
29 ;---------------------------------------------------------------------------\r
30 ; Mode X (320x240, 256 colors) rectangle solid colour fill routine.\r
31 ;\r
32 ; Based on code originally published in DDJ Mag by M. Abrash\r
33 ;\r
34 ; with TASM 2. C near-callable as:\r
35 ;\r
36 ;    void x_rect_fill_clipped(int StartX, int StartY, int EndX, int EndY,\r
37 ;       unsigned int PageBase, unsigne int color);\r
38 ;\r
39 ;\r
40 \r
41 \r
42 _x_rect_fill_clipped proc\r
43 ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Color:word\r
44         push bp              ;preserve caller's stack frame\r
45         mov  bp,sp           ;point to local stack frame\r
46         push si              ;preserve caller's register variables\r
47         push di\r
48 \r
49         mov   dx,[_TopClip]           ; Compare u.l. Y coord with Top\r
50         mov   cx,[_BottomClip]\r
51         mov   ax,[StartY]\r
52         mov   bx,[EndY]\r
53         cmp   dx,ax\r
54         jle   @@CheckBottomClip\r
55         cmp   dx,bx\r
56         jg    @@NotVisible\r
57         mov   [StartY],dx\r
58 \r
59 @@CheckBottomClip:\r
60         cmp   cx,bx\r
61         jg    @@CheckLeftClip\r
62         cmp   cx,ax\r
63         jl    @@NotVisible\r
64         mov   [EndY],cx\r
65 \r
66 @@CheckLeftClip:\r
67         mov   dx,[_LeftClip]           ; Compare u.l. Y coord with Top\r
68         mov   cx,[_RightClip]\r
69         mov   ax,[StartX]\r
70         mov   bx,[EndX]\r
71         sal   dx,2\r
72         sal   cx,2\r
73         cmp   dx,ax\r
74         jle   @@CheckRightClip\r
75         cmp   dx,bx\r
76         jg    @@NotVisible\r
77         mov   [StartX],dx\r
78 \r
79 @@CheckRightClip:\r
80         cmp   cx,bx\r
81         jg    RFClipDone\r
82         cmp   cx,ax\r
83         jl    @@NotVisible\r
84         mov   [EndX],cx\r
85         jmp   RFClipDone\r
86 \r
87 @@NotVisible:\r
88         mov   ax,1\r
89         pop   di                          ; restore registers\r
90         pop   si\r
91         pop   bp\r
92         ret\r
93 _x_rect_fill_clipped endp\r
94 \r
95 \r
96 \r
97 ;---------------------------------------------------------------------------\r
98 ; Mode X (320x240, 256 colors) rectangle solid colour fill routine.\r
99 ;\r
100 ; Based on code originally published in DDJ Mag by M. Abrash\r
101 ;\r
102 ; with TASM 2. C near-callable as:\r
103 ;\r
104 ;    void x_rect_fill(int StartX, int StartY, int EndX, int EndY,\r
105 ;       unsigned int PageBase, unsigne int color);\r
106 ;\r
107 ;\r
108 \r
109 \r
110 _x_rect_fill proc\r
111 ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Color:word\r
112         push bp              ;preserve caller's stack frame\r
113         mov  bp,sp           ;point to local stack frame\r
114         push si              ;preserve caller's register variables\r
115         push di\r
116 \r
117 RFClipDone:\r
118         cld\r
119         mov  ax,[_ScrnLogicalByteWidth]\r
120         mul  [StartY]            ;offset in page of top rectangle scan line\r
121         mov  di,[StartX]\r
122         sar  di,2                ;X/4 = offset of first rectangle pixel in scan\r
123         add  di,ax               ;offset of first rectangle pixel in page\r
124         add  di,[PageBase]       ;offset of first rectangle pixel in\r
125                                  ; display memory\r
126         mov  ax,SCREEN_SEG       ;point ES:DI to the first rectangle\r
127         mov  es,ax               ; pixel's address\r
128         mov  dx,SC_INDEX         ;set the Sequence Controller Index to\r
129         mov  al,MAP_MASK         ; point to the Map Mask register\r
130         out  dx,al\r
131         inc  dx                  ;point DX to the SC Data register\r
132         mov  si,[StartX]\r
133         and  si,0003h                    ;look up left edge plane mask\r
134         mov  bh,LeftClipPlaneMask[si]    ; to clip & put in BH\r
135         mov  si,[EndX]\r
136         and  si,0003h                    ;look up right edge plane\r
137         mov  bl,RightClipPlaneMask[si]   ; mask to clip & put in BL\r
138 \r
139         mov  cx,[EndX]                   ;calculate # of addresses across rect\r
140         mov  si,[StartX]\r
141         cmp  cx,si\r
142         jle  @@FillDone                  ;skip if 0 or negative width\r
143         dec  cx\r
144         and  si,not 011b\r
145         sub  cx,si\r
146         sar  cx,2                 ;# of addresses across rectangle to fill - 1\r
147         jnz  @@MasksSet           ;there's more than one byte to draw\r
148         and  bh,bl                ;there's only one byte, so combine the left\r
149                                   ; and right edge clip masks\r
150 @@MasksSet:\r
151         mov  si,[EndY]\r
152         sub  si,[StartY]            ;BX = height of rectangle\r
153         jle  @@FillDone             ;skip if 0 or negative height\r
154         mov  ah,byte ptr [Color]    ;color with which to fill\r
155         mov  bp,[_ScrnLogicalByteWidth]  ;stack frame isn't needed any more\r
156         sub  bp,cx                  ;distance from end of one scan line to start\r
157         dec  bp                     ; of next\r
158 @@FillRowsLoop:\r
159         push cx                     ;remember width in addresses - 1\r
160         mov  al,bh                  ;put left-edge clip mask in AL\r
161         out  dx,al                  ;set the left-edge plane (clip) mask\r
162         mov  al,ah                  ;put color in AL\r
163         stosb                       ;draw the left edge\r
164         dec  cx                     ;count off left edge byte\r
165         js   @@FillLoopBottom       ;that's the only byte\r
166         jz   @@DoRightEdge          ;there are only two bytes\r
167         mov  al,00fh                ;middle addresses drawn 4 pixels at a pop\r
168         out  dx,al                  ;set the middle pixel mask to no clip\r
169         mov  al,ah                  ;put color in AL\r
170         rep  stosb                  ;draw middle addresses four pixels apiece\r
171 @@DoRightEdge:\r
172         mov  al,bl                  ;put right-edge clip mask in AL\r
173         out  dx,al                  ;set the right-edge plane (clip) mask\r
174         mov  al,ah                  ;put color in AL\r
175         stosb                       ;draw the right edge\r
176 @@FillLoopBottom:\r
177         add  di,bp                  ;point to start of the next scan line of\r
178                                     ; the rectangle\r
179         pop  cx                     ;retrieve width in addresses - 1\r
180         dec  si                     ;count down scan lines\r
181         jnz  @@FillRowsLoop\r
182 @@FillDone:\r
183         pop  di                     ;restore caller's register variables\r
184         pop  si\r
185         pop  bp                     ;restore caller's stack frame\r
186         ret\r
187 _x_rect_fill endp\r
188 \r
189 \r
190 \r
191 ;---------------------------------------------------------------------------\r
192 ; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine.\r
193 ; Upper left corner of pattern is always aligned to a multiple-of-4\r
194 ; row and column. Works on all VGAs. Uses approach of copying the\r
195 ; pattern to off-screen display memory, then loading the latches with\r
196 ; the pattern for each scan line and filling each scan line four\r
197 ; pixels at a time. Fills up to but not including the column at EndX\r
198 ; and the row at EndY. No clipping is performed. All ASM code tested\r
199 ;\r
200 ;\r
201 ; Based on code originally published in DDJ Mag by M. Abrash\r
202 ;\r
203 ;\r
204 ;  C near-callable as:\r
205 ;\r
206 ;    void x_rect_pattern_clipped(int StartX, int StartY, int EndX, int EndY,\r
207 ;       unsigned int PageBase, char far * Pattern);\r
208 ;\r
209 ;\r
210 \r
211 _x_rect_pattern_clipped proc\r
212 ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword\r
213 LOCAL   NextScanOffset:word,RectAddrWidth:word,Height:word=LocalStk\r
214         push bp                       ;preserve caller's stack frame\r
215         mov  bp,sp                    ;point to local stack frame\r
216         sub  sp,LocalStk              ;allocate space for local vars\r
217         push si                       ;preserve caller's register variables\r
218         push di\r
219         push ds\r
220 \r
221         mov   dx,[_TopClip]           ; Compare u.l. Y coord with Top\r
222         mov   cx,[_BottomClip]\r
223         mov   ax,[StartY]\r
224         mov   bx,[EndY]\r
225         cmp   dx,ax\r
226         jle   @@CheckBottomClip\r
227         cmp   dx,bx\r
228         jg    @@NotVisible\r
229         mov   [StartY],dx\r
230 \r
231 @@CheckBottomClip:\r
232         cmp   cx,bx\r
233         jg    @@CheckLeftClip\r
234         cmp   cx,ax\r
235         jl    @@NotVisible\r
236         mov   [EndY],cx\r
237 \r
238 @@CheckLeftClip:\r
239         mov   dx,[_LeftClip]           ; Compare u.l. Y coord with Top\r
240         mov   cx,[_RightClip]\r
241         mov   ax,[StartX]\r
242         mov   bx,[EndX]\r
243         sal   dx,2\r
244         sal   cx,2\r
245         cmp   dx,ax\r
246         jle   @@CheckRightClip\r
247         cmp   dx,bx\r
248         jg    @@NotVisible\r
249         mov   [StartX],dx\r
250 \r
251 @@CheckRightClip:\r
252         cmp   cx,bx\r
253         jg    RPClipDone\r
254         cmp   cx,ax\r
255         jl    @@NotVisible\r
256         mov   [EndX],cx\r
257         jmp   RPClipDone\r
258 \r
259 @@NotVisible:\r
260         mov   ax,1\r
261         pop   ds\r
262         pop   di                          ; restore registers\r
263         pop   si\r
264         mov   sp,bp\r
265         pop   bp\r
266         ret\r
267 \r
268 _x_rect_pattern_clipped endp\r
269 \r
270 ;---------------------------------------------------------------------------\r
271 ; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine.\r
272 ; Upper left corner of pattern is always aligned to a multiple-of-4\r
273 ; row and column. Works on all VGAs. Uses approach of copying the\r
274 ; pattern to off-screen display memory, then loading the latches with\r
275 ; the pattern for each scan line and filling each scan line four\r
276 ; pixels at a time. Fills up to but not including the column at EndX\r
277 ; and the row at EndY. No clipping is performed. All ASM code tested\r
278 ;\r
279 ;\r
280 ; Based on code originally published in DDJ Mag by M. Abrash\r
281 ;\r
282 ;\r
283 ;  C near-callable as:\r
284 ;\r
285 ;    void x_rect_pattern(int StartX, int StartY, int EndX, int EndY,\r
286 ;       unsigned int PageBase, char far * Pattern);\r
287 \r
288 \r
289 \r
290 _x_rect_pattern proc\r
291 ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword\r
292 LOCAL   NextScanOffset:word,RectAddrWidth:word,Height:word=LocalStk\r
293         push bp                       ;preserve caller's stack frame\r
294         mov  bp,sp                    ;point to local stack frame\r
295         sub  sp,LocalStk              ;allocate space for local vars\r
296         push si                       ;preserve caller's register variables\r
297         push di\r
298         push ds\r
299 \r
300 RPClipDone:\r
301         cld\r
302         mov  ax,SCREEN_SEG            ;point ES to display memory\r
303         mov  es,ax\r
304                                       ;copy pattern to display memory buffer\r
305         lds  si,dword ptr [Pattern]   ;point to pattern to fill with\r
306         mov  di,PATTERN_BUFFER        ;point ES:DI to pattern buffer\r
307         mov  dx,SC_INDEX              ;point Sequence Controller Index to\r
308         mov  al,MAP_MASK              ; Map Mask\r
309         out  dx,al\r
310         inc  dx                       ;point to SC Data register\r
311         mov  cx,4                     ;4 pixel quadruplets in pattern\r
312 @@DownloadPatternLoop:\r
313         mov  al,1                     ;\r
314         out  dx,al                    ;select plane 0 for writes\r
315         movsb                         ;copy over next plane 0 pattern pixel\r
316         dec  di                       ;stay at same address for next plane\r
317         mov  al,2                     ;\r
318         out  dx,al                    ;select plane 1 for writes\r
319         movsb                         ;copy over next plane 1 pattern pixel\r
320         dec  di                       ;stay at same address for next plane\r
321         mov  al,4                     ;\r
322         out  dx,al                    ;select plane 2 for writes\r
323         movsb                         ;copy over next plane 2 pattern pixel\r
324         dec  di                       ;stay at same address for next plane\r
325         mov  al,8                     ;\r
326         out  dx,al                    ;select plane 3 for writes\r
327         movsb                         ;copy over next plane 3 pattern pixel\r
328                                       ; and advance address\r
329         loop @@DownloadPatternLoop\r
330         pop  ds\r
331 \r
332         mov  dx,GC_INDEX              ;set the bit mask to select all bits\r
333         mov  ax,00000h+BIT_MASK       ; from the latches and none from\r
334         out  dx,ax                    ; the CPU, so that we can write the\r
335                                       ; latch contents directly to memory\r
336         mov  ax,[StartY]              ;top rectangle scan line\r
337         mov  si,ax\r
338         and  si,011b                  ;top rect scan line modulo 4\r
339         add  si,PATTERN_BUFFER        ;point to pattern scan line that\r
340                                       ; maps to top line of rect to draw\r
341         mov  dx,[_ScrnLogicalByteWidth]\r
342         mul  dx                       ;offset in page of top rect scan line\r
343         mov  di,[StartX]\r
344         mov  bx,di\r
345         sar  di,2             ;X/4 = offset of first rectangle pixel in scan\r
346         add  di,ax                    ;offset of first rectangle pixel in page\r
347         add  di,[PageBase]            ;offset of first rectangle pixel in\r
348                                       ; display memory\r
349         and  bx,0003h                 ;look up left edge plane mask\r
350         mov  ah,LeftClipPlaneMask[bx] ; to clip\r
351         mov  bx,[EndX]\r
352         and  bx,0003h                  ;look up right edge plane\r
353         mov  al,RightClipPlaneMask[bx] ; mask to clip\r
354         mov  bx,ax                     ;put the masks in BX\r
355 \r
356         mov  cx,[EndX]                 ;calculate # of addresses across rect\r
357         mov  ax,[StartX]\r
358         cmp  cx,ax\r
359         jle  @@FillDone                ;skip if 0 or negative width\r
360         dec  cx\r
361         and  ax,not 011b\r
362         sub  cx,ax\r
363         sar  cx,2                 ;# of addresses across rectangle to fill - 1\r
364         jnz  @@MasksSet           ;there's more than one pixel to draw\r
365         and  bh,bl                ;there's only one pixel, so combine the left\r
366                                   ; and right edge clip masks\r
367 @@MasksSet:\r
368         mov  ax,[EndY]\r
369         sub  ax,[StartY]          ;AX = height of rectangle\r
370         jle  @@FillDone           ;skip if 0 or negative height\r
371         mov  [Height],ax\r
372         mov  ax,[_ScrnLogicalByteWidth]\r
373         sub  ax,cx                ;distance from end of one scan line to start\r
374         dec  ax                   ; of next\r
375         mov  [NextScanOffset],ax\r
376         mov  [RectAddrWidth],cx   ;remember width in addresses - 1\r
377         mov  dx,SC_INDEX+1        ;point to Sequence Controller Data reg\r
378                                   ; (SC Index still points to Map Mask)\r
379 @@FillRowsLoop:\r
380         mov  cx,[RectAddrWidth]   ;width across - 1\r
381         mov  al,es:[si]           ;read display memory to latch this scan\r
382                                   ; line's pattern\r
383         inc  si                   ;point to the next pattern scan line, wrapping\r
384         jnz  short @@NoWrap       ; back to the start of the pattern if\r
385         sub  si,4                 ; we've run off the end\r
386 @@NoWrap:\r
387         mov  al,bh                ;put left-edge clip mask in AL\r
388         out  dx,al                ;set the left-edge plane (clip) mask\r
389         stosb                     ;draw the left edge (pixels come from latches;\r
390                                   ; value written by CPU doesn't matter)\r
391         dec  cx                   ;count off left edge address\r
392         js   @@FillLoopBottom     ;that's the only address\r
393         jz   @@DoRightEdge        ;there are only two addresses\r
394         mov  al,00fh              ;middle addresses drawn 4 pixels at a pop\r
395         out  dx,al                ;set middle pixel mask to no clip\r
396         rep  stosb                ;draw middle addresses four pixels apiece\r
397                                   ; (from latches; value written doesn't matter)\r
398 @@DoRightEdge:\r
399         mov  al,bl                ;put right-edge clip mask in AL\r
400         out  dx,al                ;set the right-edge plane (clip) mask\r
401         stosb                     ;draw the right edge (from latches; value\r
402                                   ; written doesn't matter)\r
403 @@FillLoopBottom:\r
404         add  di,[NextScanOffset]  ;point to the start of the next scan\r
405                                   ; line of the rectangle\r
406         dec  word ptr [Height]    ;count down scan lines\r
407         jnz  @@FillRowsLoop\r
408 @@FillDone:\r
409         mov  dx,GC_INDEX+1        ;restore the bit mask to its default,\r
410         mov  al,0ffh              ; which selects all bits from the CPU\r
411         out  dx,al                ; and none from the latches (the GC\r
412                                   ; Index still points to Bit Mask)\r
413 \r
414         pop  di                   ;restore caller's register variables\r
415         pop  si\r
416         mov  sp,bp                ;discard storage for local variables\r
417         pop  bp                   ;restore caller's stack frame\r
418         ret\r
419 _x_rect_pattern endp\r
420 \r
421 ;-----------------------------------------------------------------------\r
422 ; Mode X (320x240, 256 colors) display memory to display memory copy\r
423 ; routine. Left edge of source rectangle modulo 4 must equal left edge\r
424 ; of destination rectangle modulo 4. Works on all VGAs. Uses approach\r
425 ; of reading 4 pixels at a time from the source into the latches, then\r
426 ; writing the latches to the destination. Copies up to but not\r
427 ; including the column at SrcEndX and the row at SrcEndY. No\r
428 ; clipping is performed. Results are not guaranteed if the source and\r
429 ; destination overlap.\r
430 ;\r
431 ;\r
432 ; Based on code originally published in DDJ Mag by M. Abrash\r
433 ;\r
434 ;C near-callable as:\r
435 ;    void x_cp_vid_rect(int SrcStartX, int SrcStartY,\r
436 ;       int SrcEndX, int SrcEndY, int DestStartX,\r
437 ;       int DestStartY, unsigned int SrcPageBase,\r
438 ;       unsigned int DestPageBase, int SrcBitmapWidth,\r
439 ;       int DestBitmapWidth);\r
440 \r
441 _x_cp_vid_rect proc\r
442         ARG SrcStartX:word,SrcStartY:word,SrcEndX:word,SrcEndY:word,DestStartX:word,DestStartY:word,SrcPageBase:word,DestPageBase:word,SrcBitmapW:word,DestBitmapW:word\r
443         LOCAL SrcNextOffs:word,DestNextOffs:word,RectAddrW:word,Height:word=LocalStk\r
444         push    bp                  ;preserve caller's stack frame\r
445         mov     bp,sp               ;point to local stack frame\r
446         sub     sp,LocalStk         ;allocate space for local vars\r
447         push    si                  ;preserve caller's register variables\r
448         push    di\r
449         push    ds\r
450 \r
451         cld\r
452         mov     dx,GC_INDEX         ;set the bit mask to select all bits\r
453         mov     ax,00000h+BIT_MASK  ; from the latches and none from\r
454         out dx,ax                   ; the CPU, so that we can write the\r
455                                     ; latch contents directly to memory\r
456         mov     ax,SCREEN_SEG       ;point ES to display memory\r
457         mov     es,ax\r
458         mov     ax,[DestBitmapW]\r
459         shr     ax,2                ;convert to width in addresses\r
460         mul     [DestStartY]        ;top dest rect scan line\r
461         mov     di,[DestStartX]\r
462         sar     di,2                ;X/4 = offset of first dest rect pixel in\r
463                                     ; scan line\r
464         add     di,ax               ;offset of first dest rect pixel in page\r
465         add     di,[DestPageBase]   ;offset of first dest rect pixel\r
466                                     ; in display memory\r
467         mov     ax,[SrcBitmapW]\r
468         sar     ax,2                ;convert to width in addresses\r
469         mul     [SrcStartY]      ;top source rect scan line\r
470         mov     si,[SrcStartX]\r
471         mov     bx,si\r
472         sar     si,2              ;X/4 = offset of first source rect pixel in\r
473                                   ; scan line\r
474         add     si,ax             ;offset of first source rect pixel in page\r
475         add     si,[SrcPageBase]  ;offset of first source rect\r
476                                   ; pixel in display memory\r
477         and     bx,0003h                     ;look up left edge plane mask\r
478         mov     ah,LeftClipPlaneMask[bx]  ; to clip\r
479         mov     bx,[SrcEndX]\r
480         and     bx,0003h                     ;look up right edge plane\r
481         mov     al,RightClipPlaneMask[bx] ; mask to clip\r
482         mov     bx,ax                        ;put the masks in BX\r
483 \r
484         mov     cx,[SrcEndX]              ;calculate # of addresses across\r
485         mov     ax,[SrcStartX]            ; rect\r
486         cmp     cx,ax\r
487         jle     @@CopyDone                   ;skip if 0 or negative width\r
488         dec     cx\r
489         and     ax,not 011b\r
490         sub     cx,ax\r
491         sar     cx,2             ;# of addresses across rectangle to copy - 1\r
492         jnz     @@MasksSet       ;there's more than one address to draw\r
493         and     bh,bl            ;there's only one address, so combine the left\r
494                                  ; and right edge clip masks\r
495 @@MasksSet:\r
496         mov     ax,[SrcEndY]\r
497         sub     ax,[SrcStartY]     ;AX = height of rectangle\r
498         jle     @@CopyDone         ;skip if 0 or negative height\r
499         mov     [Height],ax\r
500         mov     ax,[DestBitmapW]\r
501         sar     ax,2               ;convert to width in addresses\r
502         sub     ax,cx              ;distance from end of one dest scan line\r
503         dec     ax                 ; to start of next\r
504         mov     [DestNextOffs],ax\r
505         mov     ax,[SrcBitmapW]\r
506         sar     ax,2               ;convert to width in addresses\r
507         sub     ax,cx              ;distance from end of one source scan line\r
508         dec     ax                 ; to start of next\r
509         mov     [SrcNextOffs],ax\r
510         mov     [RectAddrW],cx     ;remember width in addresses - 1\r
511         mov     dx,SC_INDEX+1      ;point to Sequence Controller Data reg\r
512                                    ; (SC Index still points to Map Mask)\r
513         mov     ax,es              ;DS=ES=screen segment for MOVS\r
514         mov     ds,ax\r
515 @@CopyRowsLoop:\r
516         mov     cx,[RectAddrW]     ;width across - 1\r
517         mov     al,bh              ;put left-edge clip mask in AL\r
518         out     dx,al              ;set the left-edge plane (clip) mask\r
519         movsb                      ;copy the left edge (pixels go through\r
520                                    ; latches)\r
521         dec     cx                 ;count off left edge address\r
522         js      @@CopyLoopBottom   ;that's the only address\r
523         jz      @@DoRightEdge      ;there are only two addresses\r
524         mov     al,00fh            ;middle addresses are drawn 4 pix per go\r
525         out     dx,al              ;set the middle pixel mask to no clip\r
526         rep     movsb              ;draw the middle addresses four pix per go\r
527                                    ; (pixels copied through latches)\r
528 @@DoRightEdge:\r
529         mov     al,bl   ;put right-edge clip mask in AL\r
530         out     dx,al   ;set the right-edge plane (clip) mask\r
531         movsb           ;draw the right edge (pixels copied through\r
532                         ; latches)\r
533 @@CopyLoopBottom:\r
534         add     si,[SrcNextOffs]   ;point to the start of\r
535         add     di,[DestNextOffs]  ; next source & dest lines\r
536         dec     word ptr [Height]  ;count down scan lines\r
537         jnz     @@CopyRowsLoop\r
538 @@CopyDone:\r
539         mov     dx,GC_INDEX+1   ;restore the bit mask to its default,\r
540         mov     al,0ffh         ; which selects all bits from the CPU\r
541         out     dx,al           ; and none from the latches (the GC\r
542                                 ; Index still points to Bit Mask)\r
543         pop     ds\r
544         pop     di              ;restore caller's register variables\r
545         pop     si\r
546         mov     sp,bp           ;discard storage for local variables\r
547         pop     bp              ;restore caller's stack frame\r
548         ret\r
549 _x_cp_vid_rect  endp\r
550 \r
551 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
552 ; Copy a rectangular region of a VGA screen, with x coordinates\r
553 ; rounded to the nearest byte -- source and destination may overlap.\r
554 ;\r
555 ; C near-callable as:\r
556 ;\r
557 ; void x_shift_rect (WORD SrcLeft, WORD SrcTop,\r
558 ;                    WORD SrcRight, WORD SrcBottom,\r
559 ;                    WORD DestLeft, WORD DestTop, WORD ScreenOffs);\r
560 ;\r
561 ; SrcRight is rounded up, and the left edges are rounded down, to ensure\r
562 ; that the pixels pointed to by the arguments are inside the rectangle.\r
563 ;\r
564 ; The width of the rectangle in bytes (width in pixels / 4)\r
565 ; cannot exceed 255.\r
566 ;\r
567 ; ax, bx, cx, dx, and es eat hot lead.\r
568 ;\r
569 ; This function was written by Matthew MacKenzie\r
570 ; matm@eng.umd.edu\r
571 \r
572         align   2\r
573 _x_shift_rect proc\r
574 ARG     SrcLeft,SrcTop,SrcRight,SrcBottom,DestLeft,DestTop,ScreenOffs:word\r
575 LOCAL   width_temp:word=LocalStk\r
576 \r
577         push bp\r
578         mov bp, sp\r
579         sub sp, LocalStk\r
580         push si\r
581         push di\r
582         push ds\r
583 \r
584         ; find values for width & x motion\r
585         mov si, SrcLeft     ; source x in bytes\r
586         sar si, 2\r
587 \r
588         mov di, DestLeft    ; destination x in bytes\r
589         sar di, 2\r
590 \r
591         mov bx, SrcRight    ; right edge of source in bytes, rounded up\r
592         add bx, 3\r
593         sar bx, 2\r
594         sub bx, si\r
595         mov ax, bx          ; width - 1\r
596         inc bx              ; we'll use this as an offset for moving up or down\r
597         mov width_temp, bx\r
598 \r
599         cld                 ; by default, strings increment\r
600 \r
601         cmp si, di\r
602         jge @@MovingLeft\r
603 \r
604 ; we're moving our rectangle right, so we copy it from right to left\r
605         add si, ax          ; source & destination will start on the right edge\r
606         add di, ax\r
607         neg bx\r
608         std                 ; strings decrement\r
609 \r
610 @@MovingLeft:\r
611 \r
612 ; find values for height & y motion\r
613         mov cx, _ScrnLogicalByteWidth ; bytes to move to advance one line\r
614         mov ax, SrcTop\r
615         mov dx, DestTop     ; default destination y\r
616         cmp ax, dx\r
617         jge @@MovingUp\r
618 \r
619 ; we're moving our rectangle down, so we copy it from bottom to top\r
620         mov ax, SrcBottom   ; source starts at bottom\r
621         add dx, ax          ; add (height - 1) to destination y\r
622         sub dx, SrcTop\r
623         neg cx              ; advance up screen rather than down\r
624 \r
625 @@MovingUp:\r
626         push dx             ; save destination y during multiply\r
627         mul _ScrnLogicalByteWidth\r
628         add si, ax          ; add y in bytes to source\r
629         pop ax              ; restore destination y\r
630         mul _ScrnLogicalByteWidth\r
631         add di, ax          ; add y in bytes to destination\r
632 \r
633         sub cx, bx          ; final value for moving up or down\r
634 \r
635         add si, ScreenOffs  ; source & destination are on the same screen\r
636         add di, ScreenOffs\r
637 \r
638         mov dx, SC_INDEX    ; set map mask to all four planes\r
639         mov ax, 00f02h\r
640         out dx, ax\r
641 \r
642         mov dx, GC_INDEX    ; set bit mask to take data from latches\r
643         mov ax, BIT_MASK    ;  rather than CPU\r
644         out dx, ax\r
645 \r
646         mov ax, SCREEN_SEG  ; source and destination are VGA memory\r
647         mov es, ax\r
648         mov ds, ax\r
649 \r
650         mov ah, byte ptr width_temp ; width in bytes should fit in 8 bits\r
651 \r
652         mov bx, SrcBottom   ; height - 1\r
653         sub bx, SrcTop\r
654 \r
655         mov dx, cx          ; bytes to add to advance one line\r
656 \r
657         xor ch, ch          ; ready to rock\r
658 \r
659 @@LineLoop:\r
660         mov cl, ah          ; load width in bytes\r
661         rep movsb           ; move 4 pixels at a time using latches (YOW!)\r
662 \r
663         add si, dx          ; advance source by one line\r
664         add di, dx          ; advance destination by one line\r
665 \r
666         dec bx              ; line counter\r
667         jge @@LineLoop      ; 0 still means one more to go\r
668 \r
669         mov dx, GC_INDEX + 1; set bit mask to take data from CPU (normal setting)\r
670         mov al, 0ffh\r
671         out dx, al\r
672 \r
673 ; kick\r
674         pop ds\r
675         pop di\r
676         pop si\r
677         mov sp, bp\r
678         pop bp\r
679 \r
680         ret\r
681 _x_shift_rect endp\r
682 \r
683         end\r
684 \r