1 ;-----------------------------------------------------------------------
\r
4 ; Rectangle functions all MODE X 256 Color resolutions
\r
10 ; ****** XLIB - Mode X graphics library ****************
\r
11 ; ****** ****************
\r
12 ; ****** Written By Themie Gouthas ****************
\r
14 ; egg@dstos3.dsto.gov.au
\r
15 ; teg@bart.dsto.gov.au
\r
16 ;-----------------------------------------------------------------------
\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
29 ;---------------------------------------------------------------------------
\r
30 ; Mode X (320x240, 256 colors) rectangle solid colour fill routine.
\r
32 ; Based on code originally published in DDJ Mag by M. Abrash
\r
34 ; with TASM 2. C near-callable as:
\r
36 ; void x_rect_fill_clipped(int StartX, int StartY, int EndX, int EndY,
\r
37 ; unsigned int PageBase, unsigne int color);
\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
49 mov dx,[_TopClip] ; Compare u.l. Y coord with Top
\r
50 mov cx,[_BottomClip]
\r
54 jle @@CheckBottomClip
\r
67 mov dx,[_LeftClip] ; Compare u.l. Y coord with Top
\r
74 jle @@CheckRightClip
\r
89 pop di ; restore registers
\r
93 _x_rect_fill_clipped endp
\r
97 ;---------------------------------------------------------------------------
\r
98 ; Mode X (320x240, 256 colors) rectangle solid colour fill routine.
\r
100 ; Based on code originally published in DDJ Mag by M. Abrash
\r
102 ; with TASM 2. C near-callable as:
\r
104 ; void x_rect_fill(int StartX, int StartY, int EndX, int EndY,
\r
105 ; unsigned int PageBase, unsigne int color);
\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
119 mov ax,[_ScrnLogicalByteWidth]
\r
120 mul [StartY] ;offset in page of top rectangle scan line
\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
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
131 inc dx ;point DX to the SC Data register
\r
133 and si,0003h ;look up left edge plane mask
\r
134 mov bh,LeftClipPlaneMask[si] ; to clip & put in BH
\r
136 and si,0003h ;look up right edge plane
\r
137 mov bl,RightClipPlaneMask[si] ; mask to clip & put in BL
\r
139 mov cx,[EndX] ;calculate # of addresses across rect
\r
142 jle @@FillDone ;skip if 0 or negative width
\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
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
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
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
177 add di,bp ;point to start of the next scan line of
\r
179 pop cx ;retrieve width in addresses - 1
\r
180 dec si ;count down scan lines
\r
183 pop di ;restore caller's register variables
\r
185 pop bp ;restore caller's stack frame
\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
201 ; Based on code originally published in DDJ Mag by M. Abrash
\r
204 ; C near-callable as:
\r
206 ; void x_rect_pattern_clipped(int StartX, int StartY, int EndX, int EndY,
\r
207 ; unsigned int PageBase, char far * Pattern);
\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
221 mov dx,[_TopClip] ; Compare u.l. Y coord with Top
\r
222 mov cx,[_BottomClip]
\r
226 jle @@CheckBottomClip
\r
239 mov dx,[_LeftClip] ; Compare u.l. Y coord with Top
\r
240 mov cx,[_RightClip]
\r
246 jle @@CheckRightClip
\r
262 pop di ; restore registers
\r
268 _x_rect_pattern_clipped endp
\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
280 ; Based on code originally published in DDJ Mag by M. Abrash
\r
283 ; C near-callable as:
\r
285 ; void x_rect_pattern(int StartX, int StartY, int EndX, int EndY,
\r
286 ; unsigned int PageBase, char far * Pattern);
\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
302 mov ax,SCREEN_SEG ;point ES to display memory
\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
310 inc dx ;point to SC Data register
\r
311 mov cx,4 ;4 pixel quadruplets in pattern
\r
312 @@DownloadPatternLoop:
\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
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
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
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
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
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
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
349 and bx,0003h ;look up left edge plane mask
\r
350 mov ah,LeftClipPlaneMask[bx] ; to clip
\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
356 mov cx,[EndX] ;calculate # of addresses across rect
\r
359 jle @@FillDone ;skip if 0 or negative width
\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
369 sub ax,[StartY] ;AX = height of rectangle
\r
370 jle @@FillDone ;skip if 0 or negative height
\r
372 mov ax,[_ScrnLogicalByteWidth]
\r
373 sub ax,cx ;distance from end of one scan line to start
\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
380 mov cx,[RectAddrWidth] ;width across - 1
\r
381 mov al,es:[si] ;read display memory to latch this scan
\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
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
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
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
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
414 pop di ;restore caller's register variables
\r
416 mov sp,bp ;discard storage for local variables
\r
417 pop bp ;restore caller's stack frame
\r
419 _x_rect_pattern endp
\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
432 ; Based on code originally published in DDJ Mag by M. Abrash
\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
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
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
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
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
472 sar si,2 ;X/4 = offset of first source rect pixel in
\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
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
484 mov cx,[SrcEndX] ;calculate # of addresses across
\r
485 mov ax,[SrcStartX] ; rect
\r
487 jle @@CopyDone ;skip if 0 or negative width
\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
497 sub ax,[SrcStartY] ;AX = height of rectangle
\r
498 jle @@CopyDone ;skip if 0 or negative height
\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
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
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
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
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
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
544 pop di ;restore caller's register variables
\r
546 mov sp,bp ;discard storage for local variables
\r
547 pop bp ;restore caller's stack frame
\r
549 _x_cp_vid_rect endp
\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
555 ; C near-callable as:
\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
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
564 ; The width of the rectangle in bytes (width in pixels / 4)
\r
565 ; cannot exceed 255.
\r
567 ; ax, bx, cx, dx, and es eat hot lead.
\r
569 ; This function was written by Matthew MacKenzie
\r
574 ARG SrcLeft,SrcTop,SrcRight,SrcBottom,DestLeft,DestTop,ScreenOffs:word
\r
575 LOCAL width_temp:word=LocalStk
\r
584 ; find values for width & x motion
\r
585 mov si, SrcLeft ; source x in bytes
\r
588 mov di, DestLeft ; destination x in bytes
\r
591 mov bx, SrcRight ; right edge of source in bytes, rounded up
\r
595 mov ax, bx ; width - 1
\r
596 inc bx ; we'll use this as an offset for moving up or down
\r
599 cld ; by default, strings increment
\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
608 std ; strings decrement
\r
612 ; find values for height & y motion
\r
613 mov cx, _ScrnLogicalByteWidth ; bytes to move to advance one line
\r
615 mov dx, DestTop ; default destination y
\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
623 neg cx ; advance up screen rather than down
\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
633 sub cx, bx ; final value for moving up or down
\r
635 add si, ScreenOffs ; source & destination are on the same screen
\r
638 mov dx, SC_INDEX ; set map mask to all four planes
\r
642 mov dx, GC_INDEX ; set bit mask to take data from latches
\r
643 mov ax, BIT_MASK ; rather than CPU
\r
646 mov ax, SCREEN_SEG ; source and destination are VGA memory
\r
650 mov ah, byte ptr width_temp ; width in bytes should fit in 8 bits
\r
652 mov bx, SrcBottom ; height - 1
\r
655 mov dx, cx ; bytes to add to advance one line
\r
657 xor ch, ch ; ready to rock
\r
660 mov cl, ah ; load width in bytes
\r
661 rep movsb ; move 4 pixels at a time using latches (YOW!)
\r
663 add si, dx ; advance source by one line
\r
664 add di, dx ; advance destination by one line
\r
666 dec bx ; line counter
\r
667 jge @@LineLoop ; 0 still means one more to go
\r
669 mov dx, GC_INDEX + 1; set bit mask to take data from CPU (normal setting)
\r