1 ;-----------------------------------------------------------
\r
3 ; MXFP.ASM - Fade palette function
\r
4 ; Copyright (c) 1992-1994 ARTIS s.r.l.
\r
5 ; Author: Alessandro Scotti
\r
7 ;-----------------------------------------------------------
\r
11 PUBLIC mxFadePalette
\r
17 ; The actual speed of fading depends on the number of passes (FADE_SPEED) and
\r
18 ; the delay between two consecutive passes (FADE_DELAY). Below are the
\r
19 ; default values, used when no parameters are specified.
\r
21 FADE_DELAY EQU 1 ; Vert. retraces between video updates
\r
22 FADE_SPEED EQU 48 ; Speed of effect (max 127)
\r
24 ; Bit field record for fade commands
\r
26 FADE_COMMAND RECORD fpDELAY:8,fpSPEED:7,fpDIRECTION:1
\r
28 MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'
\r
29 ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING
\r
31 DB 'Copyright (c) 1992-1994 ARTIS s.r.l. All rights reserved.'
\r
33 ;-----------------------------------------------------------
\r
35 ; Fades a VGA palette.
\r
38 ; Buffer = pointer to source/destination palette
\r
39 ; Command = fading direction and optional parameters
\r
40 ; Start = index of first color to fade
\r
41 ; Count = number of color to fade
\r
42 ; Red = destination red
\r
43 ; Green = destination green
\r
44 ; Blue = destination blue
\r
48 ; - about 1.5 Kbytes of stack space are needed for internal buffers;
\r
49 ; - the Command argument usually is 0 to fade in and 1 to fade out,
\r
50 ; however additional parameters may be specified. To set the effect
\r
51 ; speed, i.e. the number of iterations needed to completely fade a
\r
52 ; palette, shift the value one bit left and "or" it with the
\r
53 ; direction bit (range is 0..127). To set the delay between two
\r
54 ; consecutive passes, shift it eight bits left (range is 0..255).
\r
56 mxFadePalette PROC FAR
\r
63 vfpPalette:DWORD = ARG_SIZE
\r
64 LOCAL bSPalette:BYTE:MAXCOLOR*3, \
\r
65 bDPalette:BYTE:MAXCOLOR*3, \
\r
70 wSpeed:WORD = AUTO_SIZE
\r
73 .push si, di, ds, es ; Save registers
\r
75 ; Check parameters and setup variables
\r
78 mov [wDelay], FADE_DELAY ; Set default delay
\r
79 mov ax, [wCommand] ; Get command word
\r
80 and ax, MASK fpDELAY ; Mask delay command
\r
81 jz @@GetSpeed ; No command, get speed
\r
85 mov cl, fpDELAY ; Get size of delay field
\r
86 shr ax, cl ; Right justify the field
\r
88 mov [wDelay], ax ; Set new delay
\r
91 mov ax, [wCommand] ; Get command
\r
92 and ax, MASK fpSPEED ; Mask speed
\r
96 mov cl, fpSPEED ; Get size of speed field
\r
97 shr ax, cl ; Right justify the field
\r
99 or ax, ax ; Any speed specified?
\r
100 jnz @@SetVariables ; Yes, set variables
\r
101 mov ax, FADE_SPEED ; Set default speed
\r
104 mov [wSpeed], ax ; Set speed
\r
105 inc ax ; Number of iterations
\r
106 mov [bLoopCount], al ; Set loop count
\r
107 mov [bLoopStep], 1 ; Assume we're fading in
\r
108 mov [bLoopIndex], 0
\r
110 ; Check bounds for bad values
\r
112 mov ax, [wStartIdx] ; Get first index
\r
113 cmp ax, MAXCOLOR ; Is in the valid range?
\r
114 jae @@Exit ; No, exit
\r
115 add ax, [wCount] ; Get last index
\r
116 cmp ax, MAXCOLOR ; Is in the valid range?
\r
117 jbe @@BoundsOk ; Yes, continue
\r
119 sub ax, [wStartIdx]
\r
120 mov [wCount], ax ; Set count to maximum value
\r
122 jz @@Exit ; Nothing to do, exit
\r
125 ; Copy the source palette in a local array: if we fade in it's ready to
\r
126 ; use, otherwise we'll overwrite it later
\r
131 add cx, ax ; CX = wCount * 3
\r
134 lea di, [bSPalette] ; ES:DI points to local palette
\r
135 mov ax, [wStartIdx]
\r
139 lds si, [vfpPalette] ; DS:SI points to user palette
\r
140 add si, ax ; Skip unused entries
\r
149 test [wCommand], MASK fpDIRECTION ; Are we fading in?
\r
150 jz @@Main ; Yes, ok to continue
\r
151 mov ax, [wSpeed] ; Get speed
\r
152 mov [bLoopIndex], al ; Exchange first and last index
\r
153 mov [bLoopStep], -1 ; Move backward
\r
154 mov ax, ss ; Overwrite our copy of
\r
155 mov ds, ax ; user palette with the
\r
156 mov es, ax ; current active palette
\r
157 lea di, [bSPalette]
\r
158 mov ax, [wStartIdx]
\r
160 call ReadPalette ; Read current palette
\r
162 ; Prepare variables and registers for fading
\r
165 mov bh, BYTE PTR [bRed] ; Destination red
\r
166 and bh, 00111111b ; Be sure it's a valid VGA value
\r
167 mov bl, BYTE PTR [bGreen] ; Destination green
\r
168 and bl, 00111111b ; Be sure it's a valid VGA value
\r
169 mov dh, BYTE PTR [bBlue] ; Destination blue
\r
170 and dh, 00111111b ; Be sure it's a valid VGA value
\r
171 mov dl, [bLoopIndex] ; Loop index
\r
172 mov ax, ss ; All tables are stored
\r
173 mov ds, ax ; in the stack segment,
\r
174 mov es, ax ; set DS and ES
\r
179 mov ax, [wCount] ; Store count in AX
\r
180 mov cx, [wSpeed] ; Set maximum speed in CX
\r
181 lea si, [bSPalette] ; DS:SI points to source palette
\r
182 lea di, [bDPalette] ; ES:DI points to dest. palette
\r
183 call RecalcPalette ; Build a faded palette
\r
185 .push bx, dx ; Save registers we need
\r
186 lea si, [bDPalette] ; DS:SI points to palette
\r
187 mov ax, [wStartIdx] ; First index to write
\r
188 mov bx, [wCount] ; Total entries to write
\r
189 mov cx, [wDelay] ; Fade delay between updates
\r
190 call WritePalette ; Write palette
\r
191 .pop bx, dx ; Restore BX and DX
\r
193 add dl, [bLoopStep] ; Change fade intensity
\r
194 dec [bLoopCount] ; Done?
\r
195 jnz @@Loop ; No, loop again
\r
198 .pop si, di, ds, es ; Restore registers
\r
202 ;------- INTERNAL USE ONLY ------------------------------------------------
\r
204 ; Calculates a partially faded palette.
\r
207 ; AX = number of entries in palette
\r
208 ; CX = maximum fade intensity (same as fade speed)
\r
209 ; DS:SI = pointer to source palette
\r
210 ; ES:DI = pointer to destination palette
\r
211 ; BH = destination red
\r
212 ; BL = destination green
\r
213 ; DH = destination blue
\r
214 ; DL = relative intensity of destination palette
\r
216 ; it's important that a new palette can be calculated in less
\r
217 ; than 1/70th of second. Fading to any RGB value requires use
\r
218 ; of "imul" instructions: "idiv" may be replaced with faster
\r
219 ; "sar", but only when the number of passes is a power of two,
\r
220 ; thus reducing the range of selectable speeds.
\r
221 ; In both cases an extimate of CPU cycles required by this
\r
222 ; procedure shows that it's too slow to run on a 4.77 Mhz 8086
\r
223 ; CPU and a 256 color palette, so we keep "idiv" and hope
\r
224 ; the target machine to be at least a 6 Mhz 80286 (that's not
\r
225 ; asking too much...).
\r
227 RecalcPalette PROC NEAR
\r
230 mov bp, ax ; Copy counter in BP
\r
232 lodsb ; Red: read value
\r
233 sub al, bh ; Subtract destination value
\r
234 imul dl ; Scale to desired weight
\r
235 idiv cl ; Put value in AL
\r
236 add al, bh ; Add destination value...
\r
237 stosb ; ...and store it
\r
238 lodsb ; Green: read value
\r
239 sub al, bl ; Subtract destination value
\r
240 imul dl ; Scale to desired weight
\r
241 idiv cl ; Put value in AL
\r
242 add al, bl ; Add destination value...
\r
243 stosb ; ...and store it
\r
244 lodsb ; Blue: read value
\r
245 sub al, dh ; Subtract destination value
\r
246 imul dl ; Scale to desired weight
\r
247 idiv cl ; Put value in AL
\r
248 add al, dh ; Add destination value...
\r
249 stosb ; ...and store it
\r
252 pop bp ; Restore BP
\r
256 ;------- INTERNAL USE ONLY ------------------------------------------------
\r
258 ; Writes a 256 color palette.
\r
261 ; AX = index of first color to write
\r
262 ; BX = number of colors to write (each color is an RGB triplet)
\r
263 ; CX = number of vertical retraces to wait before writing to DACs
\r
264 ; DS:SI = pointer to first entry of palette
\r
266 WritePalette PROC NEAR
\r
268 mov ah, al ; Save index
\r
269 mov dx, 03DAh ; Input status register
\r
273 jnz @@Delay1 ; Wait for display mode
\r
277 jz @@Delay2 ; Wait for vertical retrace mode
\r
278 loop @@Delay1 ; Repeat CX times
\r
280 mov cx, bx ; Get number of colors
\r
281 mov dx, 03C8h ; PEL write address register
\r
282 mov al, ah ; Restore index
\r
283 out dx, al ; Select index of first color
\r
284 inc dx ; PEL data register
\r
286 cli ; Disable interrupts
\r
294 loop @@Loop ; Loop until done
\r
295 sti ; Enable interrupts
\r
299 ;------- INTERNAL USE ONLY ------------------------------------------------
\r
301 ; Reads the current palette.
\r
304 ; AX = index of first color to read
\r
305 ; CX = number of colors
\r
306 ; ES:DI = pointer to destination buffer
\r
308 ReadPalette PROC NEAR
\r