;----------------------------------------------------------- ; ; MXBB.ASM - Bit block transfer ; Copyright (c) 1993,1994 by Alessandro Scotti ; ;----------------------------------------------------------- WARN PRO NOWARN RES INCLUDE MODEX.DEF PUBLIC mxBitBlt MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE' ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING EXTRN subHorizontalLineInfo : NEAR EXTRN mx_VideoSegment : WORD EXTRN mx_BytesPerLine : WORD ;----------------------------------------------------------- ; ; Moves a block of video memory. ; ; Input: ; SX, SY = source coordinates ; Width = source width ; Height = source height ; DX, DY = destination coordinates ; Output: ; none ; ; Note: overlapping regions are not allowed. ; mxBitBlt PROC FAR ARG DestY:WORD, \ DestX:WORD, \ Height:WORD, \ Width:WORD, \ SY:WORD, \ SX:WORD = ARG_SIZE LOCAL PlaneWidth:WORD:4, \ SourceOffset:WORD, \ DestOffset:WORD, \ Count:BYTE, \ ReadPlane:BYTE, \ WritePlane:BYTE, \ LeftMask:BYTE, \ RightMask:BYTE = AUTO_SIZE .enter AUTO_SIZE .push ds, si, es, di ; Exit now if null width cmp [Width], 0 je @@Exit ; Calls the proper procedure to handle transfer mov ax, [SX] and al, 03h ; AL = source plane mov dx, [DestX] and dl, 03h ; DL = destination plane mov bx, OFFSET subPlaneBlt cmp al, dl ; Same source and destination plane? jne @@BitBlt ; No, use slow procedure mov bx, OFFSET subMoveBlt @@BitBlt: call bx @@Exit: xor ax, ax .pop ds, si, es, di .leave ARG_SIZE ;----------------------------------------------------------- ; Uses write mode 1 for maximum speed. Only works if source ; and destination are plane-aligned. ; subMoveBlt PROC NEAR ; Get horizontal line info and address of destination mov bx, [DestX] mov ax, [DestY] mov cx, [Width] call subHorizontalLineInfo mov [LeftMask], al mov [RightMask], ah mov [Width], cx ; Setup segments mov ax, [mx_VideoSegment] mov ds, ax mov es, ax ; Get address of source pixel mov ax, [SY] mul [mx_BytesPerLine] mov si, [SX] .shr si, 2 add si, ax ; Set write mode 1 mov dx, GDC mov ax, 4105h out dx, ax cld ; Move left block @@L0: mov ah, [LeftMask] or ah, ah jz @@C0 mov dx, TS mov al, 02h out dx, ax ; Set write plane mask mov ax, [mx_BytesPerLine] dec ax mov cx, [Height] .push si, di @@L1: movsb add si, ax add di, ax dec cx jnz @@L1 .pop si, di inc si inc di ; Move center block @@C0: mov bx, [Width] test bx, bx jz @@R0 mov dx, TS mov ax, 0F02h out dx, ax ; Enable all planes mov ax, [mx_BytesPerLine] sub ax, bx mov dx, [Height] .push si, di @@C1: mov cx, bx ; CX = image width rep movsb ; Cannot use "movsw" here! add si, ax ; Next scan line add di, ax ; Next scan line dec dx ; All lines processed? jnz @@C1 ; No, continue .pop si, di add si, bx add di, bx ; Move right block @@R0: mov ah, [RightMask] or ah, ah jz @@Done mov dx, TS mov al, 02h out dx, ax ; Set write plane mask mov ax, [mx_BytesPerLine] dec ax mov cx, [Height] @@R1: movsb add si, ax add di, ax dec cx jnz @@R1 @@Done: mov dx, GDC mov ax, 4005h out dx, ax ; Restore write mode 0 @@Exit: ret subMoveBlt ENDP ;----------------------------------------------------------- ; Moves one plane at a time. ; subPlaneBlt PROC NEAR ; Compute extra bytes and width count for each plane mov cx, [Width] mov bx, cx shr bx, 1 shr bx, 1 ; Width for each plane and cl, 03h mov al, 00001000b shr al, cl mov si, 3 SHL 1 @@PatchLoop: mov PlaneWidth[si], bx shr al, 1 adc bx, 0 dec si dec si jge @@PatchLoop ; Get pixel addresses mov ax, [mx_VideoSegment] mov ds, ax mov es, ax mov ax, [SY] mul [mx_BytesPerLine] mov si, [SX] shr si, 1 shr si, 1 add si, ax ; DS:SI points to source mov [SourceOffset], si mov ax, [DestY] mul [mx_BytesPerLine] mov di, [DestX] shr di, 1 shr di, 1 add di, ax ; ES:DI points to destination mov [DestOffset], di ; Adjust plane for output to VGA registers mov ax, [SX] and al, 03h mov [ReadPlane], al mov cx, [DestX] and cl, 03h mov al, 00010001b shl al, cl mov [WritePlane], al ; Ready to move now cld mov [Count], 4 ; Four planes lea bx, PlaneWidth ; SS:[BX] = width in bytes for plane @@PlaneLoop: cmp WORD PTR ss:[bx], 0 je @@Done mov ah, [WritePlane] and ah, 0Fh mov al, 02h mov dx, TS out dx, ax ; Select write plane mov ah, [ReadPlane] mov al, 04h mov dx, GDC out dx, ax ; Select read plane mov dx, [Height] mov ax, [mx_BytesPerLine] sub ax, ss:[bx] ; AX = extra bytes per line @@Loop: mov cx, ss:[bx] shr cx, 1 rep movsw rcl cx, 1 rep movsb add si, ax add di, ax dec dx jnz @@Loop ; Repeat for all lines inc bx inc bx ; Select width for next plane inc [ReadPlane] and [ReadPlane], 03h ; Should be faster on 386 using jnz @@ReadPlaneOk ; BTR and ADC... inc [SourceOffset] @@ReadPlaneOk: rol [WritePlane], 1 adc [DestOffset], 0 mov si, [SourceOffset] mov di, [DestOffset] dec [Count] jnz @@PlaneLoop ; Repeat for all planes @@Done: ret subPlaneBlt ENDP mxBitBlt ENDP MX_TEXT ENDS END