]> 4ch.mooo.com Git - 16.git/blob - 16/xw/mxfp.asm
Merge branch 'master' of github.com:sparky4/16
[16.git] / 16 / xw / mxfp.asm
1 ;-----------------------------------------------------------\r
2 ;\r
3 ; MXFP.ASM - Fade palette function\r
4 ; Copyright (c) 1992-1994 ARTIS s.r.l.\r
5 ; Author: Alessandro Scotti\r
6 ;\r
7 ;-----------------------------------------------------------\r
8 WARN    PRO\r
9 INCLUDE MODEX.DEF\r
10 \r
11 PUBLIC  mxFadePalette\r
12 \r
13 MAXCOLOR        EQU     256\r
14 FADE_IN         EQU     0\r
15 FADE_OUT        EQU     1\r
16 \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
20 ;\r
21 FADE_DELAY      EQU     1               ; Vert. retraces between video updates\r
22 FADE_SPEED      EQU     48              ; Speed of effect (max 127)\r
23 \r
24 ; Bit field record for fade commands\r
25 ;\r
26 FADE_COMMAND    RECORD  fpDELAY:8,fpSPEED:7,fpDIRECTION:1\r
27 \r
28 MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'\r
29                 ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
30 \r
31 DB      'Copyright (c) 1992-1994 ARTIS s.r.l. All rights reserved.'\r
32 \r
33 ;-----------------------------------------------------------\r
34 ;\r
35 ; Fades a VGA palette.\r
36 ;\r
37 ; Input:\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
45 ; Output:\r
46 ;       none\r
47 ; Notes:\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
55 ;\r
56 mxFadePalette   PROC FAR\r
57         ARG     bBlue:WORD,                     \\r
58                 bGreen:WORD,                    \\r
59                 bRed:WORD,                      \\r
60                 wCount:WORD,                    \\r
61                 wStartIdx:WORD,                 \\r
62                 wCommand:WORD,                  \\r
63                 vfpPalette:DWORD = ARG_SIZE\r
64         LOCAL   bSPalette:BYTE:MAXCOLOR*3,      \\r
65                 bDPalette:BYTE:MAXCOLOR*3,      \\r
66                 bLoopIndex:BYTE,                \\r
67                 bLoopStep:BYTE,                 \\r
68                 bLoopCount:BYTE,                \\r
69                 wDelay:WORD,                    \\r
70                 wSpeed:WORD     = AUTO_SIZE\r
71         ASSUME  ds:NOTHING\r
72         .enter  AUTO_SIZE\r
73         .push   si, di, ds, es                  ; Save registers\r
74 ;\r
75 ; Check parameters and setup variables\r
76 ;\r
77 @@GetDelay:\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
82     IF USE286 EQ TRUE\r
83         shr     ax, fpDELAY\r
84     ELSE\r
85         mov     cl, fpDELAY                     ; Get size of delay field\r
86         shr     ax, cl                          ; Right justify the field\r
87     ENDIF\r
88         mov     [wDelay], ax                    ; Set new delay\r
89 \r
90 @@GetSpeed:\r
91         mov     ax, [wCommand]                  ; Get command\r
92         and     ax, MASK fpSPEED                ; Mask speed\r
93     IF USE286 EQ TRUE\r
94         shr     ax, fpSPEED\r
95     ELSE\r
96         mov     cl, fpSPEED                     ; Get size of speed field\r
97         shr     ax, cl                          ; Right justify the field\r
98     ENDIF\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
102 \r
103 @@SetVariables:\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
109 ;\r
110 ; Check bounds for bad values\r
111 ;\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
118         mov     ax, MAXCOLOR\r
119         sub     ax, [wStartIdx]\r
120         mov     [wCount], ax                    ; Set count to maximum value\r
121         or      ax, ax\r
122         jz      @@Exit                          ; Nothing to do, exit\r
123 @@BoundsOk:\r
124 ;\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
127 ;\r
128         mov     cx, [wCount]\r
129         mov     ax, cx\r
130         shl     ax, 1\r
131         add     cx, ax                          ; CX = wCount * 3\r
132         mov     ax, ss\r
133         mov     es, ax\r
134         lea     di, [bSPalette]                 ; ES:DI points to local palette\r
135         mov     ax, [wStartIdx]\r
136         mov     si, ax\r
137         shl     ax, 1\r
138         add     ax, si\r
139         lds     si, [vfpPalette]                ; DS:SI points to user palette\r
140         add     si, ax                          ; Skip unused entries\r
141         cld\r
142         shr     cx, 1\r
143         rep     movsw\r
144         rcl     cx, 1\r
145         rep     movsb\r
146 ;\r
147 ; Check direction\r
148 ;\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
159         mov     cx, [wCount]\r
160         call    ReadPalette                     ; Read current palette\r
161 ;\r
162 ; Prepare variables and registers for fading\r
163 ;\r
164 @@Main:\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
175 ;\r
176 ; Main loop\r
177 ;\r
178 @@Loop:\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
184 \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
192 \r
193         add     dl, [bLoopStep]                 ; Change fade intensity\r
194         dec     [bLoopCount]                    ; Done?\r
195         jnz     @@Loop                          ; No, loop again\r
196 \r
197 @@Exit:\r
198         .pop    si, di, ds, es                  ; Restore registers\r
199         .leave  ARG_SIZE\r
200 mxFadePalette   ENDP\r
201 \r
202 ;------- INTERNAL USE ONLY ------------------------------------------------\r
203 ;\r
204 ; Calculates a partially faded palette.\r
205 ;\r
206 ; Input:\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
215 ; Note:\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
226 ;\r
227 RecalcPalette   PROC NEAR\r
228         cld\r
229         push    bp                              ; Save BP\r
230         mov     bp, ax                          ; Copy counter in BP\r
231 @@Loop:\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
250         dec     bp\r
251         jnz     @@Loop\r
252         pop     bp                              ; Restore BP\r
253         ret\r
254 RecalcPalette   ENDP\r
255 \r
256 ;------- INTERNAL USE ONLY ------------------------------------------------\r
257 ;\r
258 ; Writes a 256 color palette.\r
259 ;\r
260 ; Input:\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
265 ;\r
266 WritePalette    PROC NEAR\r
267         ASSUME  ds:NOTHING\r
268         mov     ah, al                          ; Save index\r
269         mov     dx, 03DAh                       ; Input status register\r
270 @@Delay1:\r
271         in      al, dx\r
272         test    al, 08h\r
273         jnz     @@Delay1                        ; Wait for display mode\r
274 @@Delay2:\r
275         in      al, dx\r
276         test    al, 08h\r
277         jz      @@Delay2                        ; Wait for vertical retrace mode\r
278         loop    @@Delay1                        ; Repeat CX times\r
279 @@Write:\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
285         cld                                     ; Move forward\r
286         cli                                     ; Disable interrupts\r
287 @@Loop:\r
288         lodsb\r
289         out     dx, al                          ; Red\r
290         lodsb\r
291         out     dx, al                          ; Green\r
292         lodsb\r
293         out     dx, al                          ; Blue\r
294         loop    @@Loop                          ; Loop until done\r
295         sti                                     ; Enable interrupts\r
296         ret\r
297 WritePalette    ENDP\r
298 \r
299 ;------- INTERNAL USE ONLY ------------------------------------------------\r
300 ;\r
301 ; Reads the current palette.\r
302 ;\r
303 ; Input:\r
304 ;       AX      = index of first color to read\r
305 ;       CX      = number of colors\r
306 ;       ES:DI   = pointer to destination buffer\r
307 ;\r
308 ReadPalette     PROC    NEAR\r
309         mov     dx, 03C7h\r
310         out     dx, al\r
311         inc     dx\r
312         inc     dx\r
313         cld\r
314 @@Loop:\r
315         in      al, dx\r
316         stosb\r
317         in      al, dx\r
318         stosb\r
319         in      al, dx\r
320         stosb\r
321         loop    @@Loop\r
322         ret\r
323 ReadPalette     ENDP\r
324 \r
325 MX_TEXT         ENDS\r
326 END\r