title vgabox1.asm
; variation on vgabox.asm
; 	creates a complete checker pattern
; calls solid_box procedure (prog085.asm)
;       uses graphics mode 12h
.model small
if1
	include ..\..\mac\basic.mac
endif
.data
xx0	dw 0		;(xx0,yy0)=top left corner of (first) box
yy0	dw 0
width_ equ 64		; dimensions of boxes
height equ 48
no_boxes_per_row equ 10
no_boxes_per_col equ 10
ccolor dw 1			; color of first box
xoffset equ 64
yoffset equ 48
xx1 	dw ?			; (xx1,yy1)=bottom right corner of boxes
yy1	dw ?
.code
main proc
initdata		; macro
;
mov ah,0		; set screen mode
mov al,12h      	; mode 12h
int 10h
;
display_it 'Using mode 12h to display checker board in 16 default colors'
newline
;
mov cx,no_boxes_per_col
repeat_col:
push cx		; cx is messed up by someone, so must save it
mov ax,yy0		; begin update yy1
add ax,height
mov yy1,ax			; yy1 = yy0+width
mov cx,no_boxes_per_row
repeat_row:
push cx
mov ax,xx0		; begin update xx1
add ax,width_
mov xx1,ax			; xx1 = xx0+width
save <ccolor,yy1,xx1,yy0,xx0>		; setting up arguments 
call _solid_box				;   before calling _solid_box
add sp,10		; i.e., restore <ccolor, yy1, xx1, yy0, xx0>
add xx0,xoffset
inc ccolor
pop cx
loop repeat_row
add yy0,yoffset
pop cx
loop repeat_col
;
pause "press any key to terminate"
; restore mode
	mov ah,0
	mov al,3
	int 10h
;
exitdos
main endp

;************************************************************************
; solid_box(x0,y0,x1,y1,color)   fill a rectangle defined by            *
;       upper-left 'x0,y0', and lower-right 'x1,y1'                     *
;       with the specified color 'Color'.                               *
;       Each pixel on the display corresponds to one bit in memory.     *
;       Thus one byte represents 8 different pixles.                    *
;       A rectangle, in general, will consist of three vertical         *
;       strips. The midle strip will be composed entirely from pixels   *
;       forming a complete byte. The left strip has pixels only in      *
;       last few bits of a byte, and right strip only in first few bits *
;       This routine will draw each strip in a separate loop.           *
;************************************************************************

x0      EQU     [BP+4]
y0      EQU     [BP+6]
x1      EQU     [BP+8]
y1      EQU     [BP+10]
Color   EQU     [BP+12]

       ; PUBLIC  _Solid_Box

_Solid_Box      PROC NEAR
        PUSH    BP
        MOV     BP,SP
        PUSH    DI                      ;Preserve segment registers
        PUSH    SI
        PUSH    DS
        PUSH    ES

        ;--- Rearrange corners so that x0<x1 and y0<y1

        MOV     AX,X1                   ; make x0 < x1
        MOV     BX,X0
        CMP     AX,BX
        JGE     xfine
        MOV     X0,AX
        MOV     X1,BX
xfine:  MOV     AX,Y1                   ; make y0 < y1
        MOV     BX,Y0
        CMP     AX,BX
        JGE     yfine
        MOV     Y0,AX
        MOV     Y1,BX
yfine:

        ;--- COMPUTE ADDRESS AND MASK FOR FIRST PIXEL -------------

        MOV     cl,4                    ; offset = 80 * y + x/8
        MOV     AX,Y0
        SHL     AX,CL
        MOV     BX,AX
        SHL     AX,1
        SHL     AX,1
        ADD     AX,BX
        MOV     BX,X0                   ; + x/8
        MOV     CL,3
        SHR     BX,CL
        ADD     AX,BX
        MOV     DI,AX                   ; save offset in register di

       ;--- Load SET/RESET registers with current color

        MOV     DX,03CEh                ; move color into reset register
        XOR     AL,AL
        OUT     DX,AL
        INC     DX
        MOV     AL,Color
        OUT     DX,AL
        DEC     DX                      ; enable use of reset register
        MOV     AL,1
        OUT     DX,AL
        INC     DX
        MOV     AL,0Fh
        OUT     DX,AL
        MOV     DX,03C4h                ; enable all four planes for writing
        MOV     AL,2
        OUT     DX,AL
        INC     DX
        MOV     AL,0Fh
        OUT     DX,al

        ;---    load segment register

        MOV     DX,0A000h
        MOV     ES,DX
        MOV     DX,DX

;------------------- FILL LEADING PARTIAL BYTES ------------------------
; in this section first strip of the rectangle is drawn

        MOV     CX,X0                   ; check for partial leading byte by
        AND     CX,07h                  ; checking that x0 is not a multiple
        JZ      endlead                 ; of 8

        MOV     AX,X0                   ; update x0 to start in the middle strip
        SUB     AX,CX
        ADD     AX,8
        MOV     X0,AX                   ;...and save it for later

        MOV     BX,0FFh                 ; compute the mask (bits to change)
        SHR     BX,CL

        SUB     AX,X1                   ; check if whole rectangle is in
        DEC     AX                      ; this byte
        JLE     bitmask                 ; modify mask if it is the only byte
        MOV     CX,AX
        SHR     BX,CL
        SHL     BX,CL

bitmask:MOV     DX,03CEh                ; set the mask in EGA control registers
        MOV     AL,08h
        OUT     DX,AL
        INC     DX
        MOV     AL,BL
        OUT     DX,AL
                                        ; Loop to fill the whole strip
        MOV     CX,Y1                   ; set counter over rasters
        SUB     CX,Y0
        INC     CX
        MOV     BX,80                   ; byte in next raster is 80 bytes further
        PUSH    DI
looplead:
        MOV     AH,[DI]                 ; latch data(preserve unused bits in a byte)
        MOV     [DI],AL                 ; write new data(mask register will do right bits)
        ADD     DI,BX                   ; address of byte in next raster
        LOOP    looplead

        POP     DI
        INC     DI                      ; address next to first byte in this strip
endlead:
;----------------- FILL FULL BYTES --------------------------------------
; in this section the strip containing  full bytes is drawn

        MOV     CX,X1                   ; check if any more to do
        SUB     CX,X0
        JL      endtrail
        INC     CX                      ; check if any full bytes
        CMP     CX,8
        JL      endfull

        MOV     BX,Y1                   ; set counter of rasters to fill
        SUB     BX,Y0
        INC     BX

        SHR     CX,1                    ;Converts bits fill into bytes to fill
        SHR     CX,1
        SHR     CX,1

        MOV     DX,03CEh                ; set the mask in EGA control registers
        MOV     AL,08h
        OUT     DX,AL
        INC     DX
        MOV     AL,0FFH
        OUT     DX,AL

        MOV     DX,80                   ; byte in next raster is 80 bytes further
        PUSH    DI
loopfull:
        PUSH    CX                      ; loop over rasters
        PUSH    DI

        REP     STOSB                   ; set all full bytes in the same raster

        POP     DI                      ; address of first byte in next raster
        ADD     DI,DX
        POP     CX                      ; restore counter of bytes in a raster
        DEC     BX                      ; check if more rasters to do
        JG      loopfull

        POP     DI                      ; address of byte next to last one
        ADD     DI,CX                   ; in this strip
endfull:
;------------------- FILL TRAILING PARTIAL BYTES -----------------------

        MOV     CX,X1                   ; check for trailing partial byte
        INC     CX
        AND     CX,07h
        JZ      endtrail

        MOV     AX,00FFh                ; compute mask
        ROR     AX,CL


        MOV     DX,03CEh                ; set the mask
        MOV     AL,08h
        OUT     DX,AL
        INC     DX
        MOV     AL,AH
        OUT     DX,AL

        MOV     CX,Y1                   ; set counters
        SUB     CX,Y0
        INC     CX
        MOV     BX,80
looptrail:
        MOV     AL,[DI]                 ; latch data (to preserve other bits)
        MOV     [DI],AL                 ; set new data
        ADD     DI,BX
        LOOP    looptrail

        ;--- Restore PLANE ENABLE and BIT MASK registers
endtrail:
        MOV     DX,03CEh                ; Enable all 8-bits in a byte for write
        MOV     AL,08h                  ; by setting BIT MASK register to Fhex
        OUT     DX,AL
        INC     DX
        MOV     AL,0FFh
        OUT     DX,AL

        DEC     DX                      ; Disable SET/RESET function
        MOV     AL,1
        OUT     DX,AL
        INC     DX
        XOR     AX,AX
        OUT     DX,AL

;------------- CLEAN UP AND EXIT ------------------------------------------

        POP     ES
        POP     DS
        POP     SI
        POP     DI
        MOV     SP,BP
        POP     BP
        RET
_Solid_Box      ENDP

	end main

