;--------------------------------------------
; code to fade VGA in and out. Author unknown.
;+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; extern "C" void fadepalout(int start, int count)
;
; This function fades the vga palette from the values in palette
; to 0 using a 64 pass incremental RGB fade. Similar in execution to
; _fadepalin above.
;
; note: start and count are in the range 0..255, and denote the first
; palette register to process, and the number of subsequent registers
; to process. The palette argument points to an array of 768 bytes of
; DAC palette data. Only the low six bits of each byte are significant.
; Palette registers outside the specified range are not affected.
_fadepalout PROC
ARG start: WORD, count: WORD
push bp
mov bp, sp
push es
push ds
push di
push si
push dx
push cx
push bx
jmp o_go
opal db 768 dup (20) ; temporary palette area
o_go:
push cs ; get code segment into es
pop es
mov dx,offset opal ; es:dx points to start of opal
push dx ; save offset of opal
xor bx,bx
mov cx,100h
mov ax,1017h ; bios read dac registers function
int 10h ; read the palette registers into opal
pop di ; offset of opal, was in dx!
mov ax,start ; get offset of first palette byte to
mov bx,3 ; be processed
mul bx
add di,ax ; adjust offset into opal
mov ax,count ; find the number of bytes to be processed
mov bx,3
mul bx ; leave it in ax
mov cx,64 ; 64 passes through fade loop
o_fade_loop:
push cx ; save the fade loop counter
push di ; save offset of first byte processed in
mov bl,cl ; we'll use the pass number as a threshold
mov cx,ax ; load number of bytes to process into cx
o_pal_cmp_loop:
cmp bl,es:[di] ; start decrementing when palette value
jnz o_no_dec ; is equal loop count (it will stay equal
dec BYTE PTR es:[di] ; to loop count for the rest of this pass)
o_no_dec:
inc di
loop o_pal_cmp_loop ; do the next byte
mov bx,sp ; need the stack pointer for a moment
mov di,ss:[bx] ; restore offset into pal without popping
mov cx,count ; number of triplets to process
push ax ; need to use ax for port i/o
mov dx,03DAh ; CRT controller input status 1 register
o_vbi_1:
in al,dx ; watch vertical blanking bit
test al,08h ; wait for it to clear to make sure
jnz o_vbi_1 ; we're not in a blanking interval
o_vbi_2:
in al,dx ; now wait for the start of the
test al,08h ; next blanking interval
jz o_vbi_2
mov ah,BYTE PTR start ; get 1st register to process into ah
mov dx,03c8h ; DAC palette index register
o_pal_load_loop:
mov al, ah ; get next palette number to write
out dx, al ; write the register number to the dac
inc dx ; address dac data register
mov al, BYTE PTR [es:di] ; get first byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to second byte
mov al, BYTE PTR [es:di] ; get second byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to third byte
mov al, BYTE PTR [es:di] ; get third byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to first byte of next triplet
dec dx ; address the dac index register
inc ah ; point to next palette register
loop o_pal_load_loop ; process next triplet
pop ax ; restore ax
pop di ; restore the offset into pal
pop cx ; restore the fade loop counter
loop o_fade_loop ; do the next pass through the fade loop
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
pop bp
ret
_fadepalout ENDP
;+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
;+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; extern "C" void fadepalin(int start, int count, const byte* palette)
;
; This function fades the vga palette from 0 to the values in palette
; using a 64 pass incremental RGB fade.
;
; note: start and count are in the range 0..255, and denote the first
; palette register to process, and the number of subsequent registers
; to process. The palette argument points to an array of 768 bytes of
; DAC palette data. Only the low six bits of each byte are significant.
; Palette registers outside the specified range are not affected.
_fadepalin PROC
ARG start: WORD, count: WORD, palette: DWORD
push bp
mov bp, sp
push es ; we use just about everything
push ds
push di
push si
push dx
push cx
push bx
jmp go
pal db 768 dup (0) ; working palette area
go:
; setup for and make bios call to load the current dac palette
; into the table at pal
push cs ; get code segment into es
pop es
mov dx, offset pal ; es:dx points to start of pal
push dx ; save offset of pal
xor bx,bx ; need to get the current palette into
mov cx,100h ; pal using bios int 10h, 10h, 17h
mov ax,1017h ; set up and generate the interrupt
int 10h ; read the palette registers into pal
pop di ; offset of pal, was in dx!
; get the palette pointer, then calculate the offset to the
; first byte processed, based on start, and the number of
; bytes to process based on count. Use the offset to adjust
; the string pointers in si and di, and leave the byte
; count in ax
lds si,palette ; get address of target palette
mov ax,start ; get offset of first palette byte to
mov bx,3 ; be processed
mul bx
add si,ax ; adjust di and si point first byte in the
add di,ax ; target and temporary palettes
mov ax,count ; find the number of bytes to be processed
mov bx,3
mul bx ; leave it in ax
; clear the bytes in the triplets which will be operated on by
; the fade. All other registers are unaffected
push di ; save the starting offset into pal
push ax ; save the number of bytes to process
mov cx,ax ; set up a loop counter
xor ax,ax ; clear ax
rep stosb ; fill relevant range of pal with 0's
pop ax ; restore the number of bytes to process
pop di ; restore the starting offset into pal
mov cx,64 ; 64 passes through fade loop
; the fade loop will execute 64 times. On each pass the inner
; loop adjusts the working palette, then waits for a blanking
; interval, and loads the working palette into the DAC
fade_loop:
push cx ; save the fade loop counter
push di ; save offset of first byte processed in
push si ; temp and target palettes
mov bl,cl ; outer loop count into bl
mov cx,ax ; load number of bytes to process into cx
; inner loop makes one pass through the palette for each pass
; through the outer loop. Each byte is incremented if it's
; target value is one greater than the outer loop count. Using
; this logic ensures that all bytes arrive at their target values
; on the same pass through the outer loop
pal_cmp_loop:
cmp bl,ds:[si] ; start incrementing when palette value
jns no_add ; is one greater than loop count
inc BYTE PTR es:[di]
no_add:
inc si ; point to the next byte in both palettes
inc di
loop pal_cmp_loop ; do the next byte
; setup for palette load. As much as possible was moved above the
; blanking interval wait, in order to maximize the amount of the
; blanking interval remaining in which to do the palette loading
mov bx, sp
mov di, ss:[bx+02] ; restore offset into pal without
mov cx, count ; popping number of triplets to
push ax ; process need to use ax for port i/o
; monitor bit 1 of CRT controller's input status 1 register to
; sense a vertical blanking interval. Wait for any current vbi
; to end, then wait for the next full one to begin.
mov dx,03DAh ; CRT controller input status 1 register
vbi_1:
in al, dx ; watch vertical blanking bit
test al,08h ; wait for it to clear to make
jnz vbi_1 ; sure we're not in a blanking
; interval
vbi_2:
in al,dx ; now wait for the start of the
test al,08h ; next blanking interval
jz vbi_2
; load the relevant triplets from pal into the VGA DAC palette
mov ah,BYTE PTR start ; get first register to process into ah
mov dx,03c8h ; DAC palette index register
pal_load_loop:
mov al,ah ; get next palette number to write
out dx,al ; write the reg. number to the dac
inc dx ; address dac data register
mov al,BYTE PTR [es:di] ; get first byte of triplet
out dx,al ; write it to the dac data reg.
inc di ; point to second byte
mov al,BYTE PTR [es:di] ; get second byte of triplet
out dx,al ; write it to the dac data reg.
inc di ; point to third byte
mov al,BYTE PTR [es:di] ; get third byte of triplet
out dx,al ; write it to the dac data reg.
inc di ; point to 1st byte of next triplet
dec dx ; address the dac index register
inc ah ; point to next palette register
loop pal_load_loop ; process next triplet
; clean-up for the next pass through the fade loop
pop ax ; restore ax
pop si ; restore the offset into palette
pop di ; restore the offset into pal
pop cx ; restore the fade loop counter
loop fade_loop ; do the next pass through the
; fade loop
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
pop bp
ret
_fadepalin ENDP