I, as mentioned in my other posts, am making a DOS game, and I was wondering how I could do a fade in/fade out effect. The concept overall confuses me and I was wondering if anyone here could help me out.
In case you are wondering, I am compiling my code with Watcom C and TASM as my assembly compiler. Also, I am compiling these on a Windows 95 VMWare machine.
If more information is needed, I will gladly provide it!
Without knowing what graphics you are using can't really provide much specific. But 2 different approaches come to mind.
Alpha blending. Just fade it from the normal solid (alpha = 1) to transparent (alpha = 0) over a period of time. Not sure how many colours you need to really make this look good (16bit seems like it should be fine, I can't recall clearly that far back. 24bit true colour is basically what is still commonly used).
Dithering transparency. Basically for some amount of transparency you just skip drawing certain pixels of the source image entirely. For example if drawing a source image as 50% transparent, you would draw the first top-left pixel 0,0, then skip 1,0, draw 2,0, skip 3,0, etc. then on the next row you skip 0,1, draw 1,0, etc. This will work effectively even with very few colours, is faster, and also works in some places alpha just doesn't (and so is still found in some newer games, I think mostly ones that used deferred shading, although that concern is not relevant to what you are likely to do in DOS).
Modifying the hardware palette is definitely the way to if you can, but how smooth you can make it depends on the graphics mode. For example, in the CGA 4-color modes, the best you can do is to switch the high-intensity palette to the low-intensity palette, so just one intermediate between bright and black. At the other extreme of 256-color VGA, you have full 18-bit (6 bits per component) palette entries, so 62 intermediate levels between full brightness and black.
@a light breeze Ok so I managed to get it where it changes the color, and I even got it to fade out to black, but the issue is, it wont stop going to random colors after it fades to black, which is where my next issue starts…
AFObeg equ [bp+4]
AFOcnt equ [bp+6+2]
proc FadeTransition_ near
push ebx
push ecx
push edx
mov ebp,esp
push ds
push esi
push edi
push ds ; get data segment into es
pop es
mov edx, offset _WorkPalette
push edx ; save offset of opal
xor ebx, ebx
mov ecx, 100h
mov eax, 1017h ; bios read dac registers function
int 10h ; read the palette registers into opal
pop edi ; offset of opal, was in dx!
mov eax, AFObeg ; get offset of first palette byte to
mov ebx, 3 ; be processed
mul ebx
add edi, eax ; adjust offset into opal
mov eax, AFOcnt ; find the number of bytes to be processed
mov ebx, 3
mul ebx ; leave it in ax
mov ecx, 64 ; 64 passes through fade loop
o_fade_loop:
push ecx ; save the fade loop counter
push edi ; save offset of first byte processed in
mov bl, cl ; we'll use the pass number as a threshold
mov ecx, eax ; load number of bytes to process into cx
o_pal_cmp_loop:
cmp bl, es:[edi] ; start decrementing when palette value
jnz o_no_dec ; is equal loop count (it will stay equal
dec BYTE PTR es:[edi] ; to loop count for the rest of this pass)
o_no_dec:
inc edi
loop o_pal_cmp_loop ; do the next byte
mov ebx, esp ; need the stack pointer for a moment
mov di, ss:[ebx] ; restore offset into pal without popping
mov ecx, AFOcnt ; number of triplets to process
push eax ; need to use ax for port i/o
mov edx, 03DAh ; CRT controller input status 1 register
o_vbi_1:
in al, dx ; watch vertical blanking bit
test al,08h ; wait for it to clear to make sure
jnz o_vbi_1 ; we're not in a blanking interval
o_vbi_2:
in al, dx ; now wait for the start of the
test al,08h ; next blanking interval
jz o_vbi_2
mov ah, AFObeg ; get first register to process into ah
mov dx, 03c8h ; DAC palette index register
o_pal_load_loop:
mov al, ah ; get next palette number to write
out dx, al ; write the register number to the dac
inc dx ; address dac data register
mov al, BYTE PTR es:[di] ; get first byte of triplet
out dx, al ; write it to the dac data register
inc edi ; point to second byte
mov al, BYTE PTR es:[di] ; get second byte of triplet
out dx, al ; write it to the dac data register
inc edi ; point to third byte
mov al, BYTE PTR es:[di] ; get third byte of triplet
out dx, al ; write it to the dac data register
inc edi ; point to first byte of next triplet
dec edx ; address the dac index register
inc ah ; point to next palette register
loop o_pal_load_loop ; process next triplet
pop eax ; restore ax
pop edi ; restore the offset into pal
pop ecx ; restore the fade loop counter
loop o_fade_loop ; do the next pass through the fade loop
pop di
pop si
pop ds
pop bp
ret
endp
I am pretty sure that is what the issue is, but I am not very good at using assembly, and at the same time, I am trying to convert 16 bit Borland Assembly to 32 bit Watcom assembly. (I found this old demo I had downloaded like 6 years ago on my computer, and it compiled with Borland, so I am surprised that it worked this much!)
Here is what I have so far:
The function is defined as
public AckFadeOut_
WorkPalette is defined as
extrn _WorkPalette:byte
The C code I am using is
void FadeTransition(int Begin,int Count);
and I use it by doing
FadeTransition(0,255);
WorkPalette also has its own variable definition too, and it is defined as
UCHAR WorkPalette[768];
These are all the variables that I can think would be necessary… If you need more code, just let me know.
Here is a video of what it does to the game:
For anyone who is curious, this is a level select screen.
I'm not sure if you're still looking for help, this post is almost a month old, but maybe I can help. MS-DOS and assembly was a long time ago for me, so you'll have to forgive me if I'm a bit rusty. First of all, you defined WorkPalette as 768 bytes, so I'm assuming you're using good ole' 320x200x256 VGA. “a light breeze” was correct that the old VGA RAMDAC's could display 6 bits per color channel (a maximum of 262,144 potential colors, 256 at a time.), however the color value was still represented as a full byte (even if only 6 bits counted). in your o_fade_loop: you only loop though 64 times. This should be a full 256 if you're subtracting 1 at a time. I also noticed you've got some extra pushes in that loop, that's most likely the cause of some serious stack problems. For every push there must be an equivalent pop. Too many pushes, and you've got a stack overflow. Too many pop's and your machine will explode. It's best to only use pushes and pops at the beginning and end of a procedure in order to save registers that you plan to modify, then restoring them before returning. Using them in a loop is generally a cause for serious headaches.