;
;Here you go: Let me know what kind of performance you get...
;
;= Calvin =
;
;-----------------------------------------------------------------------
; MODULE XCOPY.ASM
;
; Bitmap copy functions (FAST!!!) - Video Ram <-> Video Ram
;
; Compile with Tasm.
; C callable.
;
; By Calvin French
; french@freenet.calgary.ab.ca
; (idea taken from Matt Prittchard's MODEX library)
;
; Basically:
; 1) It copies via the VGA "latches". Basically it's an internal, 
; 32bit register on the card. When you read in a byte from video
; memory (via mov al,[...] or lodsb) it loads the latches. When you
; write a byte, it writes the latches. Or something like that.
; 2) This routine only copies "solid"-ly. I don't reccomend modifying
; it to do masking. It would be very complicated and probably slower
; than planar bitmapping. It could be modified to copy only certain
; planes, but I don't
; 3) The X-size of the bitmap must be divisible by 4, since it copies
; 4 pixels at a time. This routine is set up to only do 16x16 
; bitmaps, but it can be very easily modified.
; 4) These are useful for 2 reasons: They are very fast, and secondly
; they let you do background animations very easily. If you can't
; figure this last part out, email me.
;
; Have Fun!
;
; french@freenet.calgary.ab.ca
;
; ****** XLIB - Mode X graphics library                ****************
; ******                                               ****************
; ****** Written By Themie Gouthas                     ****************
;
; egg@dstos3.dsto.gov.au
; teg@bart.dsto.gov.au
;-----------------------------------------------------------------------
 
include xlib.inc
 
; These useful little macros are from Matt's MODEX.
 
?x4     EQU <?,?,?,?>
 
OUT_16 MACRO Register, Value
   IFDIFI <Register>, <DX>         ; If DX not setup
      MOV DX, Register        ; then Select Register
   ENDIF
   IFDIFI <Value>, <AX>            ; If AX not setup
      MOV AX, Value           ; then Get Data Value
   ENDIF
   OUT DX, AX              ; Set I/O Register(s)
ENDM
 
         ; Macro to OUT a 8 bit value to an I/O Port
 
OUT_8 MACRO Register, Value
    IFDIFI <Register>, <DX>         ; If DX not setup
        MOV     DX, Register        ; then Select Register
    ENDIF
    IFDIFI <Value>, <AL>            ; If AL not Setup
                  MOV     AL, Value           ; then Get Data Value
         ENDIF
                  OUT     DX, AL              ; Set I/O Register
ENDM
 
PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8
    IFNB <R1>
        PUSH    R1              ; Save R1
        PUSHx   R2, R3, R4, R5, R6, R7, R8
    ENDIF
ENDM
 
POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8
         IFNB <R1>
                  POP     R1              ; Restore R1
                  POPx    R2, R3, R4, R5, R6, R7, R8
         ENDIF
ENDM
 
; Macro to Clear Registers to 0
 
CLR MACRO Register, R2, R3, R4, R5, R6
         IFNB <Register>
                  XOR     Register, Register      ; Set Register = 0
                  CLR R2, R3, R4, R5, R6
         ENDIF
ENDM
 
; Macros to Decrement Counter & Jump on Condition
 
LOOPx MACRO Register, Destination
         DEC     Register                ; Counter--
         JNZ     Destination             ; Jump if not 0
ENDM
 
LOOPjz MACRO Register, Destination
         DEC     Register                ; Counter--
         JZ      Destination             ; Jump if 0
ENDM
 
 
ALL_PLANES      EQU 0Fh     ; All Bit Planes Selected
 
LATCHES_ON      EQU 00008h  ; Bit Mask + Data from Latches
LATCHES_OFF     EQU 0FF08h  ; Bit Mask + Data from CPU
SC_DATA         EQU 03C5h   ; VGA Sequencer Data Port
 
 
        .code
        .386
 
        PUBLIC   _x_copy_tile
 
_x_copy_tile PROC FAR
        ARG SourceP:word, X:word, Y:word, DestP:word, DestX:word,
DestY:word
 
        push bp
        mov bp,sp

        push si
        push di
        push ds
 
        ; for calculating offsets
        mov bx,_ScrnLogicalByteWidth
 
        ; calculate source offset
        mov si,[SourceP]
        mov ax,[Y]
        mul bx                                                          ;
* Width
        add si,ax
        mov ax,[X]
        shr ax,2
        add si,ax
 
        ; calculate dest offset
        mov di,[DestP]
        mov ax,[DestY]
        mul bx
        add di,ax
        mov ax,[DestX]
        shr ax,2
        add di,ax
 
        ; calculate diff to add on per row
        sub bx,4
 
        ; initialize screen segment
        mov ax,SCREEN_SEG
        mov es,ax
        mov ds,ax
 
        ; copying uses VGA latches. read a byte and the latch is loaded.
        ; write a byte and the latch is emptied. all planes are copied
        ; and it is very fast.
        OUT_8 SC_INDEX, MAP_MASK                ; Set up for plane select
        OUT_16 GC_INDEX, BIT_MASK               ; Data from latches == on.
        OUT_8 SC_DATA, ALL_PLANES               ; Copy all Planes
 
        cld
 
        ; copy is totally unrolled.
        COPY_ROW MACRO
                mov cx,4
                rep movsb
                add si,bx
                add di,bx
        ENDM
 
        ; wow. here's some easy asm for you:
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
        COPY_ROW
 
        ; reset the copy mode
        OUT_16 GC_INDEX, LATCHES_OFF
 
        pop ds                                  ; restore data segment
        pop di                                  ; restore registers
        pop si   
        pop bp
        ret                                     ; Exit
 
_x_copy_tile ENDP



