+;; Palette operations\r
+;; Note that where needed in the macros, a "palette" refers to\r
+;; the segment handle to a 768-byte piece of memory. So palettes\r
+;; can be loaded and freed, they're not permanent, but if you want\r
+;; to use a fixed (not allocated) palette you'd better make sure\r
+;; it's segment aligned or else you can't use these macros. If it\r
+;; is, you can just supply "seg myPalette" as the 'palette' argument\r
+;; to any of these macros.\r
+\r
+;; Fade from a palette to black\r
+FADE_OFF MACRO fade,palette\r
+ mov si,0\r
+ mov ds,palette\r
+ mov bh,fade ; positive -> Gets dimmer...\r
+ mov bl,0 ; Starts exact\r
+ mov cx,64/fade+1 ; Total number of loops required\r
+ call FadePalette\r
+ ENDM\r
+\r
+;; Fade from black to a palette\r
+FADE_ON MACRO fade,palette\r
+ mov si,0\r
+ mov ds,palette\r
+ mov bh,-fade ; negative -> Gets brighter...\r
+ mov bl,64 ; Starts totally dimmed\r
+ mov cx,64/fade+1 ; Total number of loops required\r
+ call FadePalette\r
+ ENDM\r
+\r
+;; Flash from a palette to white\r
+FLASH_OFF MACRO fade,palette\r
+ mov si,0\r
+ mov ds,palette\r
+ mov bh,-fade ; negative -> gets brighter\r
+ mov bl,0 ; Starts exact\r
+ mov cx,64/fade+1 ; Total number of loops required\r
+ call FadePalette\r
+ ENDM\r
+\r
+;; Flash from white to a palette\r
+FLASH_ON MACRO fade,palette\r
+ mov si,0\r
+ mov ds,palette\r
+ mov bh,fade ; positive -> Gets dimmer...\r
+ mov bl,-64 ; Starts totally bright\r
+ mov cx,64/fade+1 ; Total number of loops required\r
+ call FadePalette\r
+ ENDM\r
+\r
+;; Save a palette into a palette-sized piece of memory\r
+PAL_SAVE MACRO palette\r
+ mov es,palette\r
+ mov di,0\r
+ call SavePalette\r
+ ENDM\r
+\r
+; Returns AX = a new segment for a palette\r
+NEW_PAL MACRO palette\r
+ mov bx,(256 * 3) / 16\r
+ mov ah,48h\r
+ int 21h\r
+ mov palette,ax\r
+ ENDM\r
+\r
+;; Black the entire palette temporarily. Used to blank the screen while\r
+;; drawing a frame before fading in.\r
+PAL_BLACK MACRO\r
+ mov ax,seg tmppal\r
+ mov ds,ax\r
+ mov si,OFFSET tmppal\r
+ mov bh,-1 ; Doesn't really matter...\r
+ mov bl,64 ; Starts totally dimmed\r
+ mov cx,1 ; Just one time -- to leave it black\r
+ call FadePalette\r
+ ENDM\r
+\r
+;; drawing a frame before fading in.\r
+PAL_WHITE MACRO\r
+ mov ax,seg tmppal\r
+ mov ds,ax\r
+ mov si,OFFSET tmppal\r
+ mov bh,-1 ; Doesn't really matter...\r
+ mov bl,-64 ; Starts totally dimmed\r
+ mov cx,1 ; Just one time -- to leave it black\r
+ call FadePalette\r
+ ENDM\r
+\r
+;; Black the entire palette temporarily. Used to blank the screen while\r
+;; drawing a frame before fading in.\r
+PAL_UPDATE MACRO\r
+ mov cx,0 ; 0 times = update\r
+ call FadePalette\r
+ ENDM\r
+\r
+WAITBORDER MACRO\r
+ LOCAL wbr1,wbr2\r
+ mov dx,INPUT_STATUS_1\r
+wbr1: in al,dx\r
+ test al,8\r
+ jnz wbr1\r
+wbr2: in al,dx\r
+ test al,8\r
+ jz wbr2\r
+ ENDM\r
+\r
+;; Fade Palette:\r
+;; The following code is modified greatly from the Future Crew's palette\r
+;; fading code. Works on blocks of 256 colors only, so far, but I might\r
+;; change it later. Also, it theoretically could "anti-fade" -- fade to\r
+;; white -- which I call flashing, so I added that ability, which was\r
+;; missing from FC's code.\r
+EVEN\r
+tmppal DB 768 dup (?) ; Stores old palette\r
+FadePalette PROC NEAR\r
+ mov ax,seg tmppal\r
+ mov es,ax\r
+\r
+FadeLoop: push cx\r
+ push si\r
+\r
+ cmp cx,0\r
+ je JustUpdate\r
+\r
+ ; Load in the colors in the palette\r
+ mov di,OFFSET tmppal ; ES:DI -> temp palette\r
+ mov cx,768 ; Reads 256*3 bytes at a time.\r
+loadpal_loop: mov al,ds:[si] ; Load one color byte\r
+ inc si\r
+ sub al,bl ; Subtract the fade amount\r
+ jge pal_more ; Limit the range by clipping\r
+ xor al,al ; to between 0 and 63\r
+ jmp pal_ok ; (there's probably a faster\r
+pal_more: cmp al,63 ; way to do it than this,\r
+ jle pal_ok ; but I don't know it)\r
+ mov al,63\r
+pal_ok: mov es:[di],al ; Store that byte in the new\r
+ inc di\r
+ dec cx ; temp palette and loop.\r
+ jnz loadpal_loop\r
+\r
+ ; Get ready to move this block of palette values\r
+JustUpdate: sti ; Let interrupts happen now,\r
+ WAITBORDER ; while waiting for a retrace,\r
+ cli ; instead of more critical times\r
+\r
+ mov dx,PEL_WRITE_REG; Set up to write to color register,\r
+ xor al,al ; starting at palette entry 0.\r
+ out dx,al\r
+ mov dx,PEL_DATA_REG ; Point at color port\r
+\r
+ ; Quickly put out the first half of the color palette\r
+ mov di,OFFSET tmppal\r
+ mov cl,(768/6)/2 ; Does 2 loops of 128 colors each.\r
+ cli ; Waits a retrace inbetween...\r
+FirstHalfLoop: REPEAT 6 ; Steps of 6 -- reduces the\r
+ mov al,es:[di] ; number of LOOP instructions\r
+ inc di\r
+ out dx,al\r
+ ENDM\r
+ dec cl\r
+ jnz FirstHalfLoop\r
+ sti\r
+\r
+ WAITBORDER ; Waits one retrace -- less flicker\r
+ mov dx,PEL_DATA_REG ; Reset DX\r
+\r
+ ; Now, quickly put out the other half of the colors.\r
+ mov cl,(768/6)/2\r
+ cli\r
+SecondHalfLoop: REPEAT 6 ; Steps of 6 -- reduces the\r
+ mov al,es:[di] ; number of LOOP instructions\r
+ inc di\r
+ out dx,al\r
+ ENDM\r
+ dec cl\r
+ jnz SecondHalfLoop\r
+\r
+ ; For the next iteration, restore everything and loop\r
+ pop si\r
+ pop cx\r
+\r
+ cmp cx,0\r
+ je JustUpdated\r
+\r
+ add bl,bh ; Change brightness by BH\r
+\r
+ dec cx\r
+ jnz FadeLoop\r
+\r
+ ; All done, re-enable interrupts and return\r
+JustUpdated: sti\r
+ ret\r
+FadePalette ENDP\r
+\r
+;; Saves the palette into the memory pointed at by DS:SI. That memory\r
+;; must be at least 768 bytes long...\r
+SavePalette PROC NEAR\r
+ mov dx,PEL_READ_REG ; Set up to read from color register,\r
+ xor al,al ; starting at palette entry 0.\r
+ out dx,al\r
+ mov dx,PEL_DATA_REG\r
+\r
+ ; Quickly read in the first half of the color palette\r
+ mov cl,(768/6)\r
+ cli\r
+ReadPalLoop: REPEAT 6 ; Steps of 6 -- reduces the\r
+ in al,dx ; number of LOOP instructions\r
+ mov es:[di],al\r
+ inc di\r
+ ENDM\r
+ dec cl\r
+ jnz ReadPalLoop\r
+ ; All done, re-enable interrupts and return\r
+ sti\r
+ ret\r
+SavePalette ENDP\r
+\r
+;; Load a palette from a file. Opens the file and reads it into\r
+;; memory (standard LoadFile) and then points the palette at that\r
+;; newly allocated memory. Also, frees old memory before it does\r
+;; any loading ...\r
+LoadPaletteFile PROC near\r
+ mov ax,segPalette\r
+ cmp ax,-1\r
+ je pal_not_loaded\r
+ mov es,ax\r
+ mov ah,49h\r
+ int 21h\r
+ mov nError,ERR_MEM\r
+ jc lp_err\r
+ mov segPalette,-1\r
+\r
+pal_not_loaded: call LoadFile\r
+ jc lp_err\r
+\r
+ mov segPalette,dx\r
+lp_err: ret\r
+LoadPaletteFile ENDP\r
+\1a
\ No newline at end of file