;----------------------------------------------------------- ; ; MXFP.ASM - Fade palette function ; Copyright (c) 1992-1994 ARTIS s.r.l. ; Author: Alessandro Scotti ; ;----------------------------------------------------------- WARN PRO INCLUDE MODEX.DEF PUBLIC mxFadePalette MAXCOLOR EQU 256 FADE_IN EQU 0 FADE_OUT EQU 1 ; The actual speed of fading depends on the number of passes (FADE_SPEED) and ; the delay between two consecutive passes (FADE_DELAY). Below are the ; default values, used when no parameters are specified. ; FADE_DELAY EQU 1 ; Vert. retraces between video updates FADE_SPEED EQU 48 ; Speed of effect (max 127) ; Bit field record for fade commands ; FADE_COMMAND RECORD fpDELAY:8,fpSPEED:7,fpDIRECTION:1 MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE' ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING DB 'Copyright (c) 1992-1994 ARTIS s.r.l. All rights reserved.' ;----------------------------------------------------------- ; ; Fades a VGA palette. ; ; Input: ; Buffer = pointer to source/destination palette ; Command = fading direction and optional parameters ; Start = index of first color to fade ; Count = number of color to fade ; Red = destination red ; Green = destination green ; Blue = destination blue ; Output: ; none ; Notes: ; - about 1.5 Kbytes of stack space are needed for internal buffers; ; - the Command argument usually is 0 to fade in and 1 to fade out, ; however additional parameters may be specified. To set the effect ; speed, i.e. the number of iterations needed to completely fade a ; palette, shift the value one bit left and "or" it with the ; direction bit (range is 0..127). To set the delay between two ; consecutive passes, shift it eight bits left (range is 0..255). ; mxFadePalette PROC FAR ARG bBlue:WORD, \ bGreen:WORD, \ bRed:WORD, \ wCount:WORD, \ wStartIdx:WORD, \ wCommand:WORD, \ vfpPalette:DWORD = ARG_SIZE LOCAL bSPalette:BYTE:MAXCOLOR*3, \ bDPalette:BYTE:MAXCOLOR*3, \ bLoopIndex:BYTE, \ bLoopStep:BYTE, \ bLoopCount:BYTE, \ wDelay:WORD, \ wSpeed:WORD = AUTO_SIZE ASSUME ds:NOTHING .enter AUTO_SIZE .push si, di, ds, es ; Save registers ; ; Check parameters and setup variables ; @@GetDelay: mov [wDelay], FADE_DELAY ; Set default delay mov ax, [wCommand] ; Get command word and ax, MASK fpDELAY ; Mask delay command jz @@GetSpeed ; No command, get speed IF USE286 EQ TRUE shr ax, fpDELAY ELSE mov cl, fpDELAY ; Get size of delay field shr ax, cl ; Right justify the field ENDIF mov [wDelay], ax ; Set new delay @@GetSpeed: mov ax, [wCommand] ; Get command and ax, MASK fpSPEED ; Mask speed IF USE286 EQ TRUE shr ax, fpSPEED ELSE mov cl, fpSPEED ; Get size of speed field shr ax, cl ; Right justify the field ENDIF or ax, ax ; Any speed specified? jnz @@SetVariables ; Yes, set variables mov ax, FADE_SPEED ; Set default speed @@SetVariables: mov [wSpeed], ax ; Set speed inc ax ; Number of iterations mov [bLoopCount], al ; Set loop count mov [bLoopStep], 1 ; Assume we're fading in mov [bLoopIndex], 0 ; ; Check bounds for bad values ; mov ax, [wStartIdx] ; Get first index cmp ax, MAXCOLOR ; Is in the valid range? jae @@Exit ; No, exit add ax, [wCount] ; Get last index cmp ax, MAXCOLOR ; Is in the valid range? jbe @@BoundsOk ; Yes, continue mov ax, MAXCOLOR sub ax, [wStartIdx] mov [wCount], ax ; Set count to maximum value or ax, ax jz @@Exit ; Nothing to do, exit @@BoundsOk: ; ; Copy the source palette in a local array: if we fade in it's ready to ; use, otherwise we'll overwrite it later ; mov cx, [wCount] mov ax, cx shl ax, 1 add cx, ax ; CX = wCount * 3 mov ax, ss mov es, ax lea di, [bSPalette] ; ES:DI points to local palette mov ax, [wStartIdx] mov si, ax shl ax, 1 add ax, si lds si, [vfpPalette] ; DS:SI points to user palette add si, ax ; Skip unused entries cld shr cx, 1 rep movsw rcl cx, 1 rep movsb ; ; Check direction ; test [wCommand], MASK fpDIRECTION ; Are we fading in? jz @@Main ; Yes, ok to continue mov ax, [wSpeed] ; Get speed mov [bLoopIndex], al ; Exchange first and last index mov [bLoopStep], -1 ; Move backward mov ax, ss ; Overwrite our copy of mov ds, ax ; user palette with the mov es, ax ; current active palette lea di, [bSPalette] mov ax, [wStartIdx] mov cx, [wCount] call ReadPalette ; Read current palette ; ; Prepare variables and registers for fading ; @@Main: mov bh, BYTE PTR [bRed] ; Destination red and bh, 00111111b ; Be sure it's a valid VGA value mov bl, BYTE PTR [bGreen] ; Destination green and bl, 00111111b ; Be sure it's a valid VGA value mov dh, BYTE PTR [bBlue] ; Destination blue and dh, 00111111b ; Be sure it's a valid VGA value mov dl, [bLoopIndex] ; Loop index mov ax, ss ; All tables are stored mov ds, ax ; in the stack segment, mov es, ax ; set DS and ES ; ; Main loop ; @@Loop: mov ax, [wCount] ; Store count in AX mov cx, [wSpeed] ; Set maximum speed in CX lea si, [bSPalette] ; DS:SI points to source palette lea di, [bDPalette] ; ES:DI points to dest. palette call RecalcPalette ; Build a faded palette .push bx, dx ; Save registers we need lea si, [bDPalette] ; DS:SI points to palette mov ax, [wStartIdx] ; First index to write mov bx, [wCount] ; Total entries to write mov cx, [wDelay] ; Fade delay between updates call WritePalette ; Write palette .pop bx, dx ; Restore BX and DX add dl, [bLoopStep] ; Change fade intensity dec [bLoopCount] ; Done? jnz @@Loop ; No, loop again @@Exit: .pop si, di, ds, es ; Restore registers .leave ARG_SIZE mxFadePalette ENDP ;------- INTERNAL USE ONLY ------------------------------------------------ ; ; Calculates a partially faded palette. ; ; Input: ; AX = number of entries in palette ; CX = maximum fade intensity (same as fade speed) ; DS:SI = pointer to source palette ; ES:DI = pointer to destination palette ; BH = destination red ; BL = destination green ; DH = destination blue ; DL = relative intensity of destination palette ; Note: ; it's important that a new palette can be calculated in less ; than 1/70th of second. Fading to any RGB value requires use ; of "imul" instructions: "idiv" may be replaced with faster ; "sar", but only when the number of passes is a power of two, ; thus reducing the range of selectable speeds. ; In both cases an extimate of CPU cycles required by this ; procedure shows that it's too slow to run on a 4.77 Mhz 8086 ; CPU and a 256 color palette, so we keep "idiv" and hope ; the target machine to be at least a 6 Mhz 80286 (that's not ; asking too much...). ; RecalcPalette PROC NEAR cld push bp ; Save BP mov bp, ax ; Copy counter in BP @@Loop: lodsb ; Red: read value sub al, bh ; Subtract destination value imul dl ; Scale to desired weight idiv cl ; Put value in AL add al, bh ; Add destination value... stosb ; ...and store it lodsb ; Green: read value sub al, bl ; Subtract destination value imul dl ; Scale to desired weight idiv cl ; Put value in AL add al, bl ; Add destination value... stosb ; ...and store it lodsb ; Blue: read value sub al, dh ; Subtract destination value imul dl ; Scale to desired weight idiv cl ; Put value in AL add al, dh ; Add destination value... stosb ; ...and store it dec bp jnz @@Loop pop bp ; Restore BP ret RecalcPalette ENDP ;------- INTERNAL USE ONLY ------------------------------------------------ ; ; Writes a 256 color palette. ; ; Input: ; AX = index of first color to write ; BX = number of colors to write (each color is an RGB triplet) ; CX = number of vertical retraces to wait before writing to DACs ; DS:SI = pointer to first entry of palette ; WritePalette PROC NEAR ASSUME ds:NOTHING mov ah, al ; Save index mov dx, 03DAh ; Input status register @@Delay1: in al, dx test al, 08h jnz @@Delay1 ; Wait for display mode @@Delay2: in al, dx test al, 08h jz @@Delay2 ; Wait for vertical retrace mode loop @@Delay1 ; Repeat CX times @@Write: mov cx, bx ; Get number of colors mov dx, 03C8h ; PEL write address register mov al, ah ; Restore index out dx, al ; Select index of first color inc dx ; PEL data register cld ; Move forward cli ; Disable interrupts @@Loop: lodsb out dx, al ; Red lodsb out dx, al ; Green lodsb out dx, al ; Blue loop @@Loop ; Loop until done sti ; Enable interrupts ret WritePalette ENDP ;------- INTERNAL USE ONLY ------------------------------------------------ ; ; Reads the current palette. ; ; Input: ; AX = index of first color to read ; CX = number of colors ; ES:DI = pointer to destination buffer ; ReadPalette PROC NEAR mov dx, 03C7h out dx, al inc dx inc dx cld @@Loop: in al, dx stosb in al, dx stosb in al, dx stosb loop @@Loop ret ReadPalette ENDP MX_TEXT ENDS END