home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
progjorn
/
pj_7_6.arc
/
PANNING.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-08-13
|
13KB
|
423 lines
;
; *** Listing 2 ***
;
; Demonstrates the interaction of the split screen and
; horizontal pel panning. On a VGA, first pans right in the top
; half while the split screen jerks around, because split screen
; pel panning suppression is disabled, then enables split screen
; pel panning suppression and pans right in the top half while the
; split screen remains stable. On an EGA, the split screen jerks
; around in both cases, because the EGA doesn't support split
; screen pel panning suppression.
;
; The jerking in the split screen occurs because the split screen
; is being pel panned (panned by single pixels--intrabyte panning),
; but is not and cannot be byte panned (panned by single bytes--
; "extrabyte" panning) because the start address of the split screen
; is forever fixed at 0.
;*********************************************************************
IS_VGA equ 1 ;set to 0 to assemble for EGA
;
VGA_SEGMENT equ 0a000h
LOGICAL_SCREEN_WIDTH equ 1024 ;# of pixels across virtual
; screen that we'll pan across
SCREEN_HEIGHT equ 350
SPLIT_SCREEN_START equ 200 ;start scan line for split screen
SPLIT_SCREEN_HEIGHT equ SCREEN_HEIGHT-SPLIT_SCREEN_START-1
CRTC_INDEX equ 3d4h ;CRT Controller Index register
AC_INDEX equ 3c0h ;Attribute Controller Index reg
OVERFLOW equ 7 ;index of Overflow reg in CRTC
MAXIMUM_SCAN_LINE equ 9 ;index of Maximum Scan Line register
; in CRTC
START_ADDRESS_HIGH equ 0ch ;index of Start Address High register
; in CRTC
START_ADDRESS_LOW equ 0dh ;index of Start Address Low register
; in CRTC
HOFFSET equ 13h ;index of Horizontal Offset register
; in CRTC
LINE_COMPARE equ 18h ;index of Line Compare reg (bits 7-0
; of split screen start scan line)
; in CRTC
AC_MODE_CONTROL equ 10h ;index of Mode Control reg in AC
PEL_PANNING equ 13h ;index of Pel Panning reg in AC
INPUT_STATUS_0 equ 3dah ;Input Status 0 register
WORD_OUTS_OK equ 1 ;set to 0 to assemble for
; computers that can't handle
; word outs to indexed VGA registers
;*********************************************************************
; Macro to output a word value to a port.
;
OUT_WORD macro
if WORD_OUTS_OK
out dx,ax
else
out dx,al
inc dx
xchg ah,al
out dx,al
dec dx
xchg ah,al
endif
endm
;*********************************************************************
MyStack segment para stack 'STACK'
db 512 dup (0)
MyStack ends
;*********************************************************************
Data segment
SplitScreenLine dw ? ;line the split screen currently
; starts after
StartAddress dw ? ;display memory offset at which
; scanning for video data starts
PelPan db ? ;current intrabyte horizontal pel
; panning setting
Data ends
;*********************************************************************
Code segment
assume cs:Code, ds:Data
;*********************************************************************
Start proc near
mov ax,Data
mov ds,ax
;
; Select mode 10h, 640x350 16-color graphics mode.
;
mov ax,0010h ;AH=0 is select mode function
;AL=10h is mode to select,
; 640x350 16-color graphics mode
int 10h
;
; Set the Offset register to make the offset from the start of one
; scan line to the start of the next the desired number of pixels.
; This gives us a virtual screen wider than the actual screen to
; pan across.
; Note that the Offset register is programmed with the logical
; screen width in words, not bytes, hence the final division by 2.
;
mov dx,CRTC_INDEX
mov ax,(LOGICAL_SCREEN_WIDTH/8/2 shl 8) or HOFFSET
OUT_WORD
;
; Set the start address to display the memory just past the split
; screen memory.
;
mov [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
call SetStartAddress
;
; Set the split screen start scan line.
;
mov [SplitScreenLine],SPLIT_SCREEN_START
call SetSplitScreenScanLine
;
; Fill the split screen portion of display memory (starting at
; offset 0) with a choppy diagonal pattern sloping left.
;
mov ax,VGA_SEGMENT
mov es,ax
sub di,di
mov dx,SPLIT_SCREEN_HEIGHT
;fill all lines in the split screen
mov ax,0FF0h ;starting fill pattern
cld
RowLoop:
mov cx,LOGICAL_SCREEN_WIDTH/8/4
;fill 1 scan line
ColumnLoop:
stosw ;draw part of a diagonal line
mov word ptr es:[di],0 ;make vertical blank spaces so
; panning effects can be seen easily
inc di
inc di
loop ColumnLoop
rol ax,1 ;shift pattern word
dec dx
jnz RowLoop
;
; Fill the portion of display memory that will be displayed in the
; normal screen (the non-split screen part of the display) with a
; choppy diagonal pattern sloping right.
;
mov di,SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
mov dx,SCREEN_HEIGHT ;fill all lines
mov ax,0c510h ;starting fill pattern
cld
RowLoop2:
mov cx,LOGICAL_SCREEN_WIDTH/8/4
;fill 1 scan line
ColumnLoop2:
stosw ;draw part of a diagonal line
mov word ptr es:[di],0 ;make vertical blank spaces so
; panning effects can be seen easily
inc di
inc di
loop ColumnLoop2
ror ax,1 ;shift pattern word
dec dx
jnz RowLoop2
;
; Pel pan the non-split screen portion of the display; because
; split screen pel panning suppression is not turned on, the split
; screen jerks back and forth as the pel panning setting cycles.
;
mov cx,200 ;pan 200 pixels to the left
call PanRight
;
; Wait for a key press (don't echo character).
;
mov ah,8 ;DOS console input without echo function
int 21h
;
; Return to the original screen location, with pel panning turned off.
;
mov [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
call SetStartAddress
mov [PelPan],0
call SetPelPan
;
; Turn on split screen pel panning suppression, so the split screen
; won't be affected by pel panning. Not done on EGA because both
; readable registers and the split screen pel panning suppression bit
; aren't supported by EGAs.
;
if IS_VGA
mov dx,INPUT_STATUS_0
in al,dx ;reset the AC Index/Data toggle to
; Index state
mov al,20h+AC_MODE_CONTROL
;bit 5 set to 1 to keep video on
mov dx,AC_INDEX ;point to AC Index/Data register
out dx,al
inc dx ;point to AC Data reg (for reads only)
in al,dx ;get the current AC Mode Control reg
or al,20h ;enable split screen pel panning
; suppression
dec dx ;point to AC Index/Data reg (Data for
; writes only)
out dx,al ;write the new AC Mode Control setting
; with split screen pel panning
; suppression turned on
endif
;
; Pel pan the non-split screen portion of the display; because
; split screen pel panning suppression is turned on, the split
; screen will not move as the pel panning setting cycles.
;
mov cx,200 ;pan 200 pixels to the left
call PanRight
;
; Wait for a key press (don't echo character).
;
mov ah,8 ;DOS console input without echo function
int 21h
;
; Return to text mode and DOS.
;
mov ax,0003h ;AH=0 is select mode function
;AL=3 is mode to select, text mode
int 10h ;return to text mode
mov ah,4ch
int 21h ;return to DOS
Start endp
;*********************************************************************
; Waits for the leading edge of the vertical sync pulse.
;
; Input: none
;
; Output: none
;
; Registers altered: AL, DX
;
WaitForVerticalSyncStart proc near
mov dx,INPUT_STATUS_0
WaitNotVerticalSync:
in al,dx
test al,08h
jnz WaitNotVerticalSync
WaitVerticalSync:
in al,dx
test al,08h
jz WaitVerticalSync
ret
WaitForVerticalSyncStart endp
;*********************************************************************
; Waits for the trailing edge of the vertical sync pulse.
;
; Input: none
;
; Output: none
;
; Registers altered: AL, DX
;
WaitForVerticalSyncEnd proc near
mov dx,INPUT_STATUS_0
WaitVerticalSync2:
in al,dx
test al,08h
jz WaitVerticalSync2
WaitNotVerticalSync2:
in al,dx
test al,08h
jnz WaitNotVerticalSync2
ret
WaitForVerticalSyncEnd endp
;*********************************************************************
; Sets the start address to the value specifed by StartAddress.
; Wait for the trailing edge of vertical sync before setting so that
; one half of the address isn't loaded before the start of the frame
; and the other half after, resulting in flicker as one frame is
; displayed with mismatched halves. The new start address won't be
; loaded until the start of the next frame; that is, one full frame
; will be displayed before the new start address takes effect.
;
; Input: none
;
; Output: none
;
; Registers altered: AX, DX
;
SetStartAddress proc near
call WaitForVerticalSyncEnd
mov dx,CRTC_INDEX
mov al,START_ADDRESS_HIGH
mov ah,byte ptr [StartAddress+1]
cli ;make sure both registers get set at once
OUT_WORD
mov al,START_ADDRESS_LOW
mov ah,byte ptr [StartAddress]
OUT_WORD
sti
ret
SetStartAddress endp
;*********************************************************************
; Sets the horizontal pel panning setting to the value specified
; by PelPan. Waits until the start of vertical sync to do so, so
; the new pel pan setting can be loaded during non-display time
; and can be ready by the start of the next frame.
;
; Input: none
;
; Output: none
;
; Registers altered: AL, DX
;
SetPelPan proc near
call WaitForVerticalSyncStart ;also resets the AC
; Index/Data toggle
; to Index state
mov dx,AC_INDEX
mov al,PEL_PANNING+20h
;bit 5 set to 1 to keep video on
out dx,al ;point the AC Index to Pel Pan reg
mov al,[PelPan]
out dx,al ;load the new Pel Pan setting
ret
SetPelPan endp
;*********************************************************************
; Sets the scan line the split screen starts after to the scan line
; specified by SplitScreenLine.
;
; Input: none
;
; Output: none
;
; All registers preserved
;
SetSplitScreenScanLine proc near
push ax
push cx
push dx
;
; Wait for the leading edge of the vertical sync pulse. This ensures
; that we don't get mismatched portions of the split screen setting
; while setting the two or three split screen registers (register 18h
; set but register 7 not yet set when a match occurs, for example),
; which could produce brief flickering.
;
call WaitForVerticalSyncStart
;
; Set the split screen scan line.
;
mov dx,CRTC_INDEX
mov ah,byte ptr [SplitScreenLine]
mov al,LINE_COMPARE
cli ;make sure all the registers get set at once
OUT_WORD ;set bits 7-0 of the split screen scan line
mov ah,byte ptr [SplitScreenLine+1]
and ah,1
mov cl,4
shl ah,cl ;move bit 8 of the split split screen scan
; line into position for the Overflow reg
mov al,OVERFLOW
if IS_VGA
;
; The Split Screen, Overflow, and Line Compare registers all contain
; part of the split screen start scan line on the VGA. We'll take
; advantage of the readable registers of the VGA to leave other bits
; in the registers we access undisturbed.
;
out dx,al ;set CRTC Index reg to point to Overflow
inc dx ;point to CRTC Data reg
in al,dx ;get the current Overflow reg setting
and al,not 10h ;turn off split screen bit 8
or al,ah ;insert the new split screen bit 8
; (works in any mode)
out dx,al ;set the new split screen bit 8
dec dx ;point to CRTC Index reg
mov ah,byte ptr [SplitScreenLine+1]
and ah,2
mov cl,3
ror ah,cl ;move bit 9 of the split split screen scan
; line into position for the Maximum Scan
; Line register
mov al,MAXIMUM_SCAN_LINE
out dx,al ;set CRTC Index reg to point to Maximum
; Scan Line
inc dx ;point to CRTC Data reg
in al,dx ;get the current Maximum Scan Line setting
and al,not 40h ;turn off split screen bit 9
or al,ah ;insert the new split screen bit 9
; (works in any mode)
out dx,al ;set the new split screen bit 9
else
;
; Only the Split Screen and Overflow registers contain part of the
; Split Screen start scan line and need to be set on the EGA.
; EGA registers are not readable, so we have to set the non-split
; screen bits of the Overflow register to a preset value, in this
; case the value for 350-scan-line modes.
;
or ah,0fh ;insert the new split screen bit 8
; (only works in 350-scan-line EGA modes)
OUT_WORD ;set the new split screen bit 8
endif
sti
pop dx
pop cx
pop ax
ret
SetSplitScreenScanLine endp
;*********************************************************************
; Pan horizontally to the right the number of pixels specified by CX.
;
; Input: CX = # of pixels by which to pan horizontally
;
; Output: none
;
; Registers altered: AX, CX, DX
;
PanRight proc near
PanLoop:
inc [PelPan]
and [PelPan],07h
jnz DoSetStartAddress
inc [StartAddress]
DoSetStartAddress:
call SetStartAddress
call SetPelPan
loop PanLoop
ret
PanRight endp
;*********************************************************************
Code ends
end Start