Today I'll cover how to fade the palette in and out, how to display text in graphicmode, how to use precalculated lists and how to use a virtual screen.
I told you how to set the palette in part 1 of the demoschool, to fade the palette is similar to setting the palette repeaditly with slightly different values. A common trick is to set all the colors of the palette to black, then draw something to the screen and finally fade the palette in. That way the whole picture will fade in simultainously no matter how much is on the screen.
Like you remember, the palette is set through ports 3c8h and 3c9h. The index of the color that shall be set first is written to port 3c8h. Then the red, green and blue values are written to port 3c9h. After 3 bytes have been written to port 3c9h the colorindex is automatically increased. To set the entire palette to black, first write 0 to port 3c8h. Then write 0 to port 3c9h 256*3 times.
Here's an example in C:
void blackpal(void) { int i; outp(0x3c8,0); for(i=0;i<256*3;i++) outp(0x3c9,0); }
To fade the palette in, the palette is sent as parameter to the function that will fade the palette, let's call it fade_in. That function should also have a local array that will hold the temporary values of the palette during the fade. First set all colors in the local palette to 0. Then enter a loop that will set the local palette, increase the values of the local palette until they have reached their "right" values. That will be maximum 64 times since the red green and blue values can be only 63 or less. Before setting the palette you should call wtsync, that waits for the vertical retrace, to avoid snow due to bad syncronisation with the electron beam.
Here's a fade_in funtion in C:
//will fade in the palette palett void fade_in(unsigned char*palett) { int i,j; unsigned char pal[256*3]; //local array for(i=0;i<256*3;i++) pal[i]=0; //set entire pal to 0 for(j=0;j<64;j++) //fade in 64 steps { outp(0x3c8,0); //Every step begins with setting color 0 wtsync(); //call wtsync to avoid snow wtsync(); //call it another time to get a slower fade //You could skip the second call to wtsync for a faster fade for(i=0;i<256*3;i++) //loop through all bytes in the palette { outp(0x3c9,pal[i]); //send a byte to 3c9h if(pal[i]<.palett[i]) pal[i]++; //compare with final value } //if it's less increase it } }
This function fades from black to the palette. Another variant is to fade from the current palette to the palette that will be set. In that case set pal to the current palette with getpal instead of black. And add in the inner loop:
if(pal[i]<.palett[i]) pal[i]++; //ignore the . it's just there because html is so weird if(pal[i]>palett[i]) pal[i]--;
In this case the color will go towards palette[i] even if it's greater. the getpal function is in the source code.
Another fade would be to fade from the current palette to black and from the current palette to white, this should be real simple if you understand the functions above.
Ex : Letter A in the BIOS dataarea
Byte Binary Decimal BYTE 0: 0 0 0 0 0 0 0 0 = 0 BYTE 1: 0 0 0 1 1 0 0 0 = 24 BYTE 2: 0 0 1 0 0 1 0 0 = 36 BYTE 3: 0 1 0 0 0 0 1 0 = 66 BYTE 4: 0 1 1 1 1 1 1 0 = 126 BYTE 5: 0 1 0 0 0 0 1 0 = 66 BYTE 6: 0 1 0 0 0 0 1 0 = 66 BYTE 7: 0 0 0 0 0 0 0 0 = 0A 0 means the backgroundcolor and a 1 means the foregroundcolor. For every bit in the pattern we want a byte. That's no problem, just shift the bits one by one and if the shifted bit was a 0 set the respective byte in chars64 to 0 else set it to the foregroundcolor. The foregroundcolor can be any of 256 possible colors. That means that the pixels in the character does not have to be in the same color. I've chosen to make the top row of every character bright and then I subtract 3 for every row making the letters darker and darker for every row.
Data for BIOS chartable begins at address F000:FA6E Every character is 8 bytes and they are in the same order as they appear in the ascii-table. The letter A has acii-value 65. The pattern for A is therefore at address F000:(FA6E + 65*8). This should be enough to understand the function getbioschars in the source.
To Display the characters I've made two functions. Showchar draws one single character to the screen (the character should be defined in chars64 or else only crap will be drawn to the screen). Show char draws all pixels even the background color. Putcharonflag draws a character in the array flag. It doesn't draw the pixel if it's 0 that makes the characters drawn with putcharonflag transparent.
for(i=0;i<.xxx;i++) sinlist[i]=sin(K*i)*20;This will make sinlist[i] vary between -20 and +20. K and xxx are constants, xxx is the length of the list and K determines the length of the waves (period of the wave).
At the same time as the flag moves in waves I draw two texts on the screen and the texts also moves in waves (movements come from the same sinlist). Even the color of the flag changes in waves all from the same sinlist. This way it looks like there's some major math going on but in reality it's only one precalculated sin-table that does all the work. The constants are #defined at the top of the code and it's easy to change them and see what happens.
Some graphicmodes have more than one page, that means that it's possible to draw to a invisible page and when you're ready make that page the visible page. This is the same thing as using a virtual screen but you don't have to allocate any memory for it and the flipping is faster. Multiple pages also make scrolling a lot easier, but mode 13h doesn't normally support multiple pages. Although it is possible to screw with the port's of the graphic card to make it support multiple pages. This is known as unchained mode 13h or mode X (resolution of real mode X is actually 320*240). I'll cove these modes later (maybe part 5 or 6).
Demo2.c contains the sourcecode for the flag and text. onlyflag.c is shorter (only the flag) and perhaps easier to understand.
This part have been perhaps too complex for the beginner so if you don't understand everything dont be sad, next part will be easier. It will cover sprites and linking pure assembly routines to C.
PS The program is still slow even though it uses precalculated tables. It would be faster with 386-specific instructions but my compiler won't allow it. If the assembly routines are written separatly and linked with the c-program you can use 386-specific instructions. I'll cover that next time. DS
Download PART 2 of the demoschool. It contains C-source, this text and the .exe in case you'd fail to compile the C-source.
96 01 05 Abe-ylon Shavedbeard s-mail: Albert Veli Spisringsg. 9 724 76 Västerås SWEDENmail:dat94avi@bilbo.mdh.se.