I can give you some more detailed information. I did not copy the TYPE information because it really doesn't need explaining, and it wouldn't copy with linebreaks anyways. In fact, nothing did...I had to add those manually. Urg! Anyways...
The TYPE you see earlier is just a collection of variables. This line essentially "collects" all of those variables and makes them "children" of another variable, this one called BmpHeader.
I normally don't advocate the use of "#1" for file handles, but dynamic file handles are a subject for another day. Anyways, this just opens the BMP file in "Binary" file mode, which means no special formatting will be done, the file will simply be read byte-for-byte.
This fetches the header information from the BMP file. It will contain all of the information you need to draw the BMP on the screen. All of this information is kept in the variable BmpHeader and can be read by using this format:
PRINT BmpHeader.id
PRINT BmpHeader.hei
etc etc etc.
You know what this does.
BmpHeader.pal contains the image's palette data. This simply assigns that data to a temporary string. Why they do this is beyond me, but whatever.
This is the way the palette registers are affected directly. Port &H3C8 is the index pointer. By setting it to 0, we're telling it to start at index 0, or the very beginning of the palette index.
The palette is stored in segments of 4 bytes. However, only three of those bytes are relevant. So, we STEP 4 to skip through the variable 4 bytes at a time.
Now we begin reading the color data from the variable. We start with the blue. Since it's a string type, and we want numeric values, we use ASC which gives us the numeric value of any string. MID$ will "extract" only the amount of data we need; in this case, 1 byte. At the end of the line, the value has to be reduced to fit into the color rules of the VGA palette. Normally, a BMP will contain a color range of 0 to 255 for each color, but in VGA land, we only have 0 to 63. The \ 4 at the end reduces the color information so it will fit in the palette register. Don't worry, everything will still look fine.
The Green information comes next. Note that the MID$ keyword's parameters now include a + 1. That simply means we're looking at the
next byte in the temporary variable we created earlier to hold the palette.
And finally, the red. Note that there is no +3; the fourth byte in the string is "worthlesss" so we don't need to care about it.
Code: Select all
OUT &H3C9, r%
OUT &H3C9, g%
OUT &H3C9, b%
Here, all of the values that we collected so far are written to the palette registers through this port, &H3C9. Notice that there isn't another call to &H3C8...conveniently, the palette index increments itself when you write three values to &H3C9, so you don't have to mess with it!
Yep.
Okay, on to the image data. In an 8-bit BMP, each pixel is stored 1 byte at a time. However, since QB doesn't have a BYTE type (huge mistake), the best we can do is STRING * 1 for reading bytes from a file.
This new temporary variable will be used by the loop later to keep track of the Y position, or scanline, of the image. It is given -1 because the PSET later will use screen values, and if you're doing a 320x200 image, you can't write to line 200 on the screen because it doesn't exist! So, reduce this by 1 so it will write from 0-199.
And this one for the X position. Same rules regarding the -1; trying to PSET at the 320th X pixel will break stuff.
Since the image is stored line-by-line, the Y loop comes first. Also, curiously, BMP files are stored upside-down. No one except Microsoft knows what the motive was for this boneheaded move.
Now that Y is taken care of, handle X too.
Here's where we get the pixel information from the BMP. Just one byte needs to be read here, since we're dealing with an 8 bit image.
Now it gets drawn to the screen. Notice the ASC; again, since we need numeric values and we only have a string, it has to be converted to numeric. The data in Pixel corresponds to the index in the palette that we set earlier.
End the loops.
Don't forget to close the file.
As you can see, this is one of the simplest image storage methods available. Rather wasteful, but simple. This code doesn't delve into a lot of things though, such as scanline optimization or even proper byte alignment issues, but it's a start.
Anyways, I hope that was helpful. If you have any other questions, feel free to ask, I'm here all day today.
