head	1.1;
access;
symbols;
locks
	yap:1.1; strict;
comment	@;; @;


1.1
date	97.11.27.09.32.40;	author yap;	state Exp;
branches;
next	;


desc
@@


1.1
log
@Initial revision
@
text
@title vgablt.asm
; basically exercises _BitBlt procedure from prog087.asm
; but we include the file vgabox.asm for drawing boxes,
;	in order to first create an interesting pattern...
; But there is the problem of data moving over itself as shown in this
;	example --
;	is there a fix?
; uses graphics mode 12h
.model small
if1
	include ..\..\mac\basic.mac
endif
.data
;**************** old data from vgabox.asm ***********************
xx0	dw 100		;(xx0,yy0)=top left corner of (first) box
yy0	dw 50
width_ equ 50		; dimensions of boxes
height equ 24
no_boxes equ 18		; number of boxes
ccolor dw 1			; color of first box
xoffset equ 25
yoffset equ 12
xx1 	dw ?			; (xx1,yy1)=bottom right corner of boxes
yy1	dw ?
;**************** new data for BitBlt ***********************
old_x dw 150
old_y dw 5			; (old_x,old_y) is the old NE corner
new_x dw 5
new_y dw 150		; (new_x,new_y) is new NE corner
blk_x dw 300
blk_y dw 200		; (blk_x,blk_y) are dimensions of move
fcn	dw 0			; logical function: 0=copy, 1=and, 2=or, 3=xor (?)
.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 16 boxes in 16 default colors'
newline
display_it 'Can you explain the phenomenon of this BitBlt operation?'
newline
;
mov cx,no_boxes
repeat:
push cx		; cx is messed up by someone, so must save it
mov ax,xx0		; begin update xx1
add ax,width_
mov xx1,ax			; xx1 = xx0+width
mov ax,yy0		; begin update yy1
add ax,height
mov yy1,ax			; yy1 = yy0+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
add yy0,yoffset
inc ccolor
pop cx
loop repeat
;
save <fcn,blk_y,blk_x,new_y,new_x,old_y,old_x>
call _BitBlt
add sp,14		; restore <fcn,blk_y,blk_x,new_y,new_x,old_y,old_x>
;
pause "press any key to terminate"
; restore mode
	mov ah,0
	mov al,3
	int 10h
;
exitdos
main endp

;
;&&&&&&&&&&&&&&&&&&&&& prog085.asm below &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
;

;************************************************************************
; 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

;&&&&&&&&&&&&&&&&&&&&& prog087.asm below &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
;
; This program exercises the function _BitBlt, that moves
;	an entire rectangular block of pixels (with additional logical function)
; Uses the vgabox.asm routine to write a sequence of boxes of various colors.
; Then use _BitBlt to move things around...

;************************************************************************
; Transfer Bit Aligned Block of dimensions Width x Height, from         *
; source, with upper left corner at (X_Src,Y_Src), to destination with  *
; upper left corner at (X_Dst,Y_Dst), using function fn.                *
; Entry:        X_Srs, Y_Src  - Source upper left                       *
;               X_Dst, Y_Dst  - Destination upper left                  *
;               BWidth,BHeight- Dimensions of the block                 *
;               Fn            - Logical function (Copy, AND, OR, XOR)   *
;************************************************************************

;xxxx add later traversing x in reverse for overlapped src and dst

X_Src   EQU     [BP+4]                  ;Formal parameters on the stack
Y_Src   EQU     [BP+6]
X_Dst   EQU     [BP+8]
Y_Dst   EQU     [BP+10]
BWidth  EQU     [BP+12]
BHeight EQU     [BP+14]
Fn      EQU     [BP+16]

HBYTES  EQU     80                      ;Number of bytes per scanline
GRF_SEG EQU     0A000H                  ;Segment for display buffer

Y_Incr          EQU     WORD PTR [BP-2] ;Local variables
First_Mask      EQU     BYTE PTR [BP-4]
InFirst         EQU     WORD PTR [BP-6]
Last_Mask       EQU     BYTE PTR [BP-8]
Read_Plane      EQU     BYTE PTR [BP-10]
Lower_Mask      EQU     BYTE PTR [BP-12]
Upper_Mask      EQU     BYTE PTR [BP-14]
Src_Address     EQU     WORD PTR [BP-16]
Dst_Address     EQU     WORD PTR [BP-18]
Block_Dx        EQU     WORD PTR [BP-20]
Block_Dy        EQU     WORD PTR [BP-22]

        PUBLIC  _BitBlt

_BitBlt PROC    NEAR
        PUSH    BP
        MOV     BP,SP

        SUB     SP,24                   ;Setup local variables

        PUSH    DS                      ;Presrve segment registers
        PUSH    ES
        PUSH    DI
        PUSH    SI

        ;-------------------------------------------------------------
        ;--- COMPUTE MASKS FOR FIRST AND LAST BYTE WITHIN A RASTER
        ;    ROTATION FACTOR, AND MASKS FOR HI AND LOW BITS AFTER ROTATION
        ;    ENABLE ROTATION AND LOGICAL FUNCTIONS IN GRAPHICS CONTROLLER
        ;-------------------------------------------------------------

        MOV     CX,X_Dst                ; NUMBER OF CLEAR BITS IN FIRST BYTE
        AND     CX,7
        MOV     First_Mask,0FFH         ; COMPUTE MASK TO CLEAR LEADING BITS
        SHR     First_Mask,CL
        MOV     AX,8
        SUB     AX,CX
        MOV     InFirst,AX

        ;MASK TO KEEP BITS IN LAST BYTE (PARTIAL BYTE)

        MOV     CX,X_Dst                ; GET ADDRESS OF LAST BIT
        ADD     CX,BWidth
        AND     CX,7                    ; POSITION JUST AFTER LAST BIT
        MOV     Last_Mask,0FFH          ; COMPUTE MASK TO KEEP BITS AFTER
        SHR     Last_Mask,CL
        NOT     Last_Mask               ; COMPLEMENT TO KEEP LEADING BITS

        ;BITS FROM SOURCE BYTE MUST BE ALLIGNED WITH BITS IN THE
        ;DESTINATION BYTE.  HERE IS COMPUTED THE ROTATION AND THE
        ;TWO MASKS NEEDED TO ISOLOTATE TWO HALVES OF THE BYTE

        ; COMPUTE ROTATION

        MOV     CX,X_Dst                ; COMPUTE BIT DISTANCE BETWEEN
        SUB     CX,X_Src                ;... BIT POSITIONS IN FIRST BYTES
        AND     CX,7                    ; ... OF SOURCE AND DESTINATION BYTES
                                        ; ... AS (SRC-DST)&7
        MOV     AX,00FFH                ;Compute masks for non-zero rotation
        ROR     AX,CL
        MOV     Lower_Mask,AL           ;Save the masks
        MOV     Upper_Mask,AH

        MOV     DX,3CEH                 ;Address of GRAPHICS controller
        MOV     AL,3                    ;Index for DATA ROTATE & FN SELECT
        OUT     DX,AL                   ;Select DATA ROTATE & FN SELECT REG
        INC     DX
        MOV     AL,CL                   ;Fetch rotate count
        MOV     AH,Fn                   ;Fetch logical function
        AND     AH,3                    ;Move logical function into
        SHL     AH,1                    ;bits 3 and 4
        SHL     AH,1
        SHL     AH,1
        OR      AL,AH
        OUT     DX,AL                   ;Write value into DATA ROTATE... reg

        ;-------------------------------------------------------------
        ;--- COMPUTE ABSOLUTE ADDRESS OF SOURCE AND DESTINATION
        ;-------------------------------------------------------------

        MOV     WORD PTR Y_Incr,HBYTES  ;Initialize y traversal as normal

        ;Because of possible overlap we must adjust direction of traversal
        ;If source block is above the destination then reverse Y traversal
        ;If source block is to the left, then reverse X traversal

        MOV     AX,Y_Src                ;Compare source and destination Y
        MOV     BX,Y_Dst
        CMP     AX,BX
        JLE     Compute_Address         ;...Leave alone if src <= dst
        ADD     AX,BHeight              ;Begin with last raster in block
        DEC     AX
        ADD     BX,BHeight
        DEC     BX
        MOV     Y_Src,AX
        MOV     Y_Dst,BX
        NEG     WORD PTR Y_Incr         ;And traverse backwards
Compute_Address:
        MOV     AX,Y_Src                ;Compute offset for source
        MOV     BX,HBYTES               ;as offset = y * 80 + x/8
        MUL     BX
        MOV     SI,X_Src
        SHR     SI,1
        SHR     SI,1
        SHR     SI,1
        ADD     SI,AX
        MOV     Src_Address,SI

        MOV     AX,Y_Dst                ;Compute offset for destination
        MOV     BX,HBYTES               ;as offset = y * 80 + x/8
        MUL     BX
        MOV     DI,X_Dst
        SHR     DI,1
        SHR     DI,1
        SHR     DI,1
        ADD     DI,AX
        MOV     Dst_Address,DI

        MOV     AX,GRF_SEG              ;Setup segment
        MOV     ES,AX
        MOV     DS,AX

        ;-------------------------------------------------------------
        ;--- ENABLE NEXT PLANE FOR READ AND WRITE
        ;-------------------------------------------------------------

        MOV     AL,3                    ;Initialize counter of planes
        MOV     Read_Plane,AL
Plane_Loop:
        MOV     AX,BWidth               ;Copy dimensions of the block
        MOV     Block_Dx,AX
        MOV     AX,BHeight
        MOV     Block_Dy,AX
        MOV     SI,Src_Address          ;Fetch source address
        MOV     DI,Dst_Address          ;Fetch destination address
        MOV     CL,Read_Plane           ;Fetch next plane to do
        MOV     AH,1                    ;Use plane number to setup value
        SHL     AH,CL                   ;for WRITE PLANE SELECT register
        MOV     DX,3C4H                 ;Fetch address of SEQUENCER
        MOV     AL,2                    ;Index for WRITE PLANE SELECT register
        OUT     DX,AL                   ;Select register
        INC     DX
        MOV     AL,AH                   ;Fetch value
        OUT     DX,AL                   ;Write value into register
        MOV     DX,3CEH                 ;Fetch address of GRAPHICS controller
        MOV     AL,4                    ;Index for READ PLANE SELECT register
        OUT     DX,AL                   ;Select register
        INC     DX
        MOV     AL,CL                   ;Fetch plane number
        OUT     DX,AL                   ;Write plane number into register
        DEC     DX
        MOV     AL,8                    ;Index for BIT MASK register
        OUT     DX,AL                   ;Select BIT MASK register
        INC     DX

        ;-------------------------------------------------------------
        ; RASTER LOOP IS DONE IN FOUR STEPS
        ; (1) MASKS AND ROTATION FACTOR IS COMPUTED TO ALIGN SRC AND DEST
        ; (2) LEADIING PARTIAL BYTE OF DESTINATION IS MODIFIED
        ; (3) FULL BYTES OF DESTINATION ARE MODIFIED
        ; (4) TRAILLING PARTIAL BYTE OF DESTINATION IS MODIFIED
        ;-------------------------------------------------------------

        ;-------------------------------------------------------------
        ;--- GET ENOUGH BITS FROM SOUCE TO CONSTRUCT FIRST PARTIAL BYTE OF DST
        ;-------------------------------------------------------------

Raster_Loop:
        MOV     CX,Block_Dx             ;Number of bits to copy
        PUSH    SI                      ;Preserve addresses for next raster loo
        PUSH    DI

        MOV     AX,X_Src                ;Check if need one or two bytes
        AND     AX,7                    ;for first byte of destination
        MOV     BX,X_Dst
        AND     BX,7
        CMP     AX,BX
        JG      Get_2_Bytes
Get_1_Byte:
        MOV     AL,First_Mask           ;Fetch mask for first partial byte
        AND     AL,Lower_Mask           ;Combine with 'lower mask'
        OUT     DX,AL                   ;Write mask into BIT MASK register
        LODSB                           ;Fetch first source byte
        MOV     AH,[DI]                 ;Latch destination
        STOSB                           ;Write first byte of destination
        MOV     AH,AL                   ;Save AL since it will be trashed by OU
        JMP     Leading_Done

Get_2_Bytes:
        MOV     AL,First_Mask           ;Fetch mask for first partial byte
        AND     AL,Upper_Mask           ;Combine with 'upper mask'
        OUT     DX,AL                   ;Write mask into BIT MASK register
        LODSB
        MOV     AH,[DI]                 ;Latch destination bits
        MOV     ES:[DI],AL              ;Write first byte

        MOV     AL,First_Mask           ;Fetch mask for first partial byte
        AND     AL,Lower_Mask           ;Combine with 'lower mask'
        OUT     DX,AL                   ;Write mask into BIT MASK register
        LODSB
        MOV     AH,[DI]                 ;Latch destination bits
        STOSB                           ;Write first byte
        MOV     AH,AL                   ;Save AL since it will be trashed by OU

Leading_Done:
        SUB     CX,InFirst              ;Update number of bits to transfer
        JLE     Raster_Done

        ;-------------------------------------------------------------
        ;--- LOOP OVER COMPLETE BYTES WITHIN A SINGLE SOURCE RASTER
        ;-------------------------------------------------------------

Full_Loop:
        CMP     CX,8                    ;If less then 8 bits to do
        JL      Full_Done               ;quit this loop

        MOV     AL,Upper_Mask           ;Fetch the 'upper mask'
        OUT     DX,AL                   ;Write mask into BIT MASK register
        MOV     AL,[DI]                 ;Latch destination bits
        MOV     [DI],AH                 ;Write half 2 for src to half 1 of dst

        MOV     AL,Lower_Mask           ;Fetch the lower mask
        OUT     DX,AL                   ;Write mask into BIT MASK register
        LODSB                           ;Fetch next source byte
        MOV     AH,[DI]                 ;Latch destination bits
        STOSB                           ;Write half 1 of src to half 2 of dst
        MOV     AH,AL                   ;Save AL since it will be trashed by OU

        SUB     CX,8                    ; DECREMENT WIDTH BY BITS TO BE DONE
        JMP     Full_Loop
Full_Done:

        ;-------------------------------------------------------------
        ;--- TRANSFER THE LAST PARTIAL BYTE
        ;-------------------------------------------------------------

Last_Partial:
        CMP     CX,0                    ;Any more bits to transfer?
        JLE     Raster_Done             ;...No, quit this raster

        MOV     AL,Last_Mask            ;Fetch mask for last partial byte
        AND     AL,Upper_Mask           ;Combine with 'upper mask'
        OUT     DX,AL                   ;Write mask into BIT MASK register
        MOV     AL,[DI]                 ;Latch destination bits
        MOV     [DI],AH                 ;Write half 2 for src to half 1 of dst

        MOV     AL,Last_Mask            ;Fetch mask for last partial byte
        AND     AL,Lower_Mask           ;Combine with 'upper mask'
        OUT     DX,AL                   ;Write mask into BIT MASK register
        LODSB                           ;Fetch next source byte
        MOV     AH,[DI]                 ;Latch destination bits
        STOSB                           ;Write half 1 of src to half 2 of dst

        ;--- ADVANCE TO THE NEXT RASTER

Raster_Done:
        POP     DI                      ;Pointers to current raster
        POP     SI
        ADD     SI,Y_Incr               ;Update pointer to point to the next
        ADD     DI,Y_Incr               ;raster
        DEC     WORD PTR Block_Dy       ;Update number of rasters to do
        JLE     Test_Plane
        JMP     Raster_Loop             ;And repeat if not all done

Test_Plane:
        DEC     Read_Plane              ;Update number of planes to do
        JL      Blit_Done
        JMP     Plane_Loop              ;And do next plane if any left to do

        ;-------------------------------------------------------------
        ;--- Clean up and exit
        ;-------------------------------------------------------------

Blit_Done:
        ;restore rotate value
        MOV     DX,3CEH                 ;Address of GRAPHICS controller
        MOV     AL,3                    ;Index for ROTATE & FN SELECT
        OUT     DX,AL                   ;Select ROTATE & FN SELECT register
        INC     DX
        XOR     AL,AL                   ;Disable rotate and set fn=copy
        OUT     DX,AL                   ;Write value into register
        ;restore bit mask
        DEC     DX
        MOV     AL,8                    ;Index for BIT MASK register
        OUT     DX,AL                   ;Select BIT MASK register
        INC     DX
        MOV     AL,0FFH                 ;Enable all 8 bits for write
        OUT     DX,AL                   ;Write value into register
        ;enable all four planes for write
        MOV     DX,3C4H                 ;Address of SEQUENCER
        MOV     AL,2                    ;Index for PLANE ENABLE register
        OUT     DX,AL                   ;Select register
        INC     DX
        MOV     AL,0FH                  ;Value to enable all four planes
        OUT     DX,AL                   ;Write value into register

        POP     SI                      ;Restore segment registers
        POP     DI
        POP     ES
        POP     DS
        MOV     SP,BP
        POP     BP
        RET
_BitBlt ENDP

	end main
@
