COMMENT ~
 PROGRAM: TEXTFADE.ASM
  AUTHOR: Denis Boyles
 RELEASE: Public Domain (Dec 15, 1996)

 COMPILE: Arrowsoft Assembler (MASM v3.0)
      OS: MS-DOS (v6.20)

 PURPOSE: demonstrate palette usage by doing a simple text fade
~

;--------------------------------------
;define default segments
;--------------------------------------

CODE SEGMENT
    ASSUME CS:CODE,DS:CODE
    ORG 0100h

;--------------------------------------
;program starts here and skips data
;--------------------------------------

MAIN:
    jmp     START

;--------------------------------------
;data used within program
;--------------------------------------

red         db  ?                      ;keep our RED value here for color
green       db  ?                      ; "    "  GREEN "    "    "    "
blue        db  ?                      ; "    "  BLUE  "    "    "    "

FillMsg     db  "The Quick Brown Fox Jumped Over The Lazy Dog. $"
TextMsg     db  00Dh,00Ah,00Ah,"Press a key to see the fade of the screen."
            db  00Dh,00Ah,'$'

;--------------------------------------
;program really starts here
;--------------------------------------

START:
    call    PrepScreen                 ;fills our screen with stuff to fade
    call    WaitKeypress               ;wait for a keypress
    call    FadeScreen                 ;fade out the displayed screen
    call    ShutDown                   ;exit program and reset text mode

;--------------------------------------
;GetRGBValue - reads RGB values
;   AL <= index of color to read
;--------------------------------------

GetRGBValue proc
    mov     DX,03C7h                   ;set up VGA port so that we can READ
    out     DX,AL                      ;the RGB values for color index AL

    add     DX,002h                    ;add 2 so we get our VGA data port

    in      AL,DX                      ;input our RED value from the VGA card
    mov     red,AL                     ;and save it in memory
    in      AL,DX                      ;input our GREEN value from the card
    mov     green,AL                   ;and save it in memory
    in      AL,DX                      ;input our BLUE value from the VGA
    mov     blue,AL                    ;and save it in memory
    ret
GetRGBValue endp

;--------------------------------------
;SetRGBValue - sets RGB value for index
;   AL <= index of color to set
;--------------------------------------

SetRGBValue proc
    mov     DX,03C8h                   ;set up VGA port so that we can WRITE
    out     DX,AL                      ;new RGB values for color index AL
    inc     DX                         ;adds 1 so we get our VGA data port

    mov     AL,red                     ;output our new RED value to the card
    out     DX,AL
    mov     AL,green                   ;output our new GREEN value
    out     DX,AL
    mov     AL,blue                    ;output our new BLUE value
    out     DX,AL
    ret
SetRGBValue endp

;--------------------------------------
;WaitRetrace - waits until vert retrace
;--------------------------------------

WaitRetrace proc
    mov     DX,03DAh                   ;set up to read CGA status port

WVR0:
    in      AL,DX                      ;read current status and test if in
    test    AL,00001000b               ;vertical retrace (bit 8)
    jnz     WVR0                       ;if we our `flush' it

WVR1:
    in      AL,DX                      ;read current status again and test if
    test    AL,00001000b               ;in vertical retrace (bit 8)
    jz      WVR1                       ;keep checking until we're in retrace
    ret
WaitRetrace endp

;--------------------------------------
;FadeOnce - fades down RGB colors once
;--------------------------------------

FadeOnce proc
    cmp     red,0                      ;is our RED value > 0?
    ja      DecRed                     ;YES then go decrease it

CheckGreen:
    cmp     green,0                    ;is our GREEN value > 0?
    ja      DecGreen                   ;YES then go decrease it

CheckBlue:
    cmp     blue,0                     ;is our BLUE value > 0?
    ja      DecBlue                    ;YES then go decrease it

    jmp     SetPal                     ;we've check our values, set new pal

DecRed:
    dec     red                        ;red = red - 1
    jmp     CheckGreen                 ;go back to check green

DecGreen:
    dec     green                      ;green = green - 1
    jmp     CheckBlue                  ;go back to check blue
DecBlue:
    dec     blue                       ;blue = blue - 1;
SetPal:
    call    WaitRetrace                ;wait for retrace so to write with no
    call    WaitRetrace                ;`snow' and provide a delay
    mov     AL,007h                    ;we're fading index 7 (light gray)
    call    SetRGBValue                ;set the new palette for index 7
    ret
FadeOnce endp

;--------------------------------------
;PrepScreen - prints stuff to fade
;--------------------------------------

PrepScreen proc
    mov     CX,45                      ;we're gona print 45 strings to screen
    mov     AH,009h                    ;DOS print an ASCID string

FillScreen:
    mov     DX,offset FillMsg          ;DS:DX -> string to print
    int     021h                       ;call DOS and print it
    loopnz  FillScreen                 ;keep looping until all printed

    mov     AH,009h                    ;DOS print an ASCID string
    mov     DX,offset TextMsg          ;DS:DX -> string to print
    int     021h                       ;call DOS to print `press' message
    ret
PrepScreen endp

;--------------------------------------
;WaitKeypress - wait for keypress
;--------------------------------------

WaitKeypress proc
    mov     AH,0                       ;BIOS keyboard wait/get keypress
    int     016h                       ;call BIOS to wait for a keypress
    ret
WaitKeypress endp

;--------------------------------------
;FadeScreen - fades out current screen
;--------------------------------------

FadeScreen proc
    mov     AL,007h                    ;we're gona fade index 7 (light gray)
    call    GetRGBValue                ;get current RGB values for that

    mov     CX,64                      ;we fade a max of 64 times since an
                                       ;RGB value goes 0-63
FS0:
    call    FadeOnce                   ;fade down the color one time
    loopnz  FS0                        ;keep looping until black
    ret
FadeScreen endp

;--------------------------------------
;ShutDown - exits program and resets
;--------------------------------------

ShutDown proc
    mov     AH,002h                    ;DOS print a character
    mov     DL,007h                    ;a bell to `notify' the end of PRG
    int     021h                       ;call DOS to beep

    mov     AX,003h                    ;BIOS video set video mode back to
    int     010h                       ;text to reset the palette

    mov     AX,04C00h                  ;DOS terminate program with code (0)
    int     021h                       ;call DOS and end program
ShutDown endp

CODE ENDS
END MAIN
