============================================================================== MASKING IN SCREEN 13 (13h) BY TEK ------------------------------------------------------------------------------ Author: Jason Jones (Tek, neozones@quickbasic.com) Created: 05/17/1999 Last Revision: 05/17/1999 Version: 1.00 Currently, my site is located at http://neozones.quickbasic.com, and I can be reached by email at neozones@quickbasic.com. My ICQ number is 825301 if you wanted to add me. What is masking? The classic definition for QBasic/QuickBASIC would be the process of displaying images via PUT (such as a character picture), without a "surrounding black block." In other words, using the normal PUT routine with a picture you drew, it will "destroy" the background. What masking aims to achieve is to draw image without destroying the background. Of course, nowadays you can snag up a graphics library program which has an auto-mask on the PUT routine, but many people want to know how to do it them- selves, "the old fashioned way". Let's say you have a 20x20 character picture. We want to be able to show it on the screen without a border around, the "blank" pixels. The array for this image might be: DIM SHARED PlayerPic%(201) Explanation: The preceding statement declares an array of 202 (0 .. 201) integer variables. This is needed to store the whole 20x20 image for these reasons because: Let's say we have image height Height, and image width Width. Screen 13 (13h) is an 8 bit colour mode, meaning that it can have up to 256 different colours displayed at a time because if we have 8 bits, that is like saying we have 2^8 possibilities. An integer is 16 bits, which is kinda like 2 sets of 8 bits. We can effectively store 2 pixels into 1 single integer, one in in the lower 8 bits, and one in the upper 8 bits. So with image Width and image Height, there are (Width * Height) pixels. Since we can store 2 pixels into 1 integer, and integer will be the data type we are using, we can use half as many elements, so we divide by 2. (Now we have 200 integers). However, we also need to store the image width and height into the array itself, so the PUT routine knows the dimensions of the image. For this reason, we add 2 integers. Bringing up up to 202. Of course, when we DIM SHARED, we can say DIM SHARED PlayerPic%(201) because that IS 202 elements, 0 included. All in all, if you have an image at coords (x1, y1, x2, y2), and you are in an 8 bit video mode (256 colours), you can use this algorithm to calculate the size of the array you'll need: Size% = (((x2 - x1 + 1) * (y2 - y1 + 1)) / 2) + 2 If our image was 20x20 and located at (1, 10)-(20, 29), then the equation would work out something like this: Size% = (((20 - 1 + 1) * (29 - 10 + 1)) / 2) + 2 Size% = ((20 * 20) / 2) + 2 Size% = (400 / 2) + 2 Size% = 200 + 2 Size% = 202 Okay, so we have said image array. And let's say you used n!Media or some other drawing program (PixelPlus 256 for instance), to make a BSAVEd image. We would load it with this code snippet, assuming the name was "player.bsv" and the tile was 20x20: (note the line numbers used only for identification processes, you needn't code them into the program). 1: DIM SHARED PlayerPic%(201) 2: DEF SEG = VARSEG(PlayerPic%(0) 3: BLOAD "player.bsv", VARPTR(PlayerPic%(0)) 4: DEF SEG 5: SCREEN 13 6: PUT (100, 120), PlayerPic%, PSET 7: END Explanation: Line 1 is our declaration of the storage space for the image in memory. In QBasic, many things are done that pertain to the current memory segment and offset. For instance, if you are bloading an image, or using PEEK or POKE, it is based off of where the current memory segment and offset are. What this line does is tell QBasic that the current memory offset should be on our array, PlayerPic%. Not only that, but the offset is that of the first element of the array (important). The first element is 0 in this case. Line 3 is the actual loading of the image, where BLOAD takes data from a file and dumps it into a memory location: the segment as we specified, and the offset which is VARPTR(PlayerPic%(0)). Line 4 is a DEF SEG with no other statements; this will return the memory segment to where it was. Line 5, of course, makes the current video mode change (presumably from text mode 0) to 13. Line 6 is a standard PUT statement, which says "place the image PlayerPic at x coord 100 and y coord 120, we want it to be shown in PSET mode, that is, it is solid." 7 ends this "useless" program. Now we come into masking. A mask shows all the places you want to show, and don't want to show, on an image. If you want parts of an image to not show up (like the space around the character tile), then it MUST be in colour 0. If we look at a colour chart of a simple 10x10 image of a ball, and we want the outer space to be transparent (thru the masking process), we must make them colour 0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 We now make a mask. All the parts we want to show thru will be colour 0, and all the parts we want to be transparent will be colour 255. The mask for this image (ball above) would have 255's where the 0's are, and 0's where the 1's are. A quick mask making bit of code might look like this (for the a tile named "player.bsv" that is 20x20): DIM SHARED PlayerPic%(201) DIM SHARED PlayerPicMask%(201) DEF SEG = VARSEG(PlayerPic%(0)) BLOAD "player.bsv", VARPTR(PlayerPic%(0)) SCREEN 13 PUT (1, 1), PlayerPic%, PSET FOR i% = 1 TO 20 FOR j% = 1 TO 20 IF POINT(i%, j%) = 0 THEN PSET (i%, j%), 255 ELSE PSET (i%, j%), 0 END IF NEXT j% NEXT i% GET (1, 1)-(20, 20), PlayerPicMask% DEF SEG = VARSEG(PlayerPicMask%(0)) BSAVE "pmask.bsv", VARPTR(PlayerPicMask%(0)), 404 END If you can understand this [freehand] code, you can see that we merely load an image and convert all the black areas to 255, and all the image areas to 0, then save it. Now on to the part you've been waiting for, the actual masking of the image for it's display. Using native BASIC commands, this is quite easy. The following code will demonstrate: DIM SHARED PlayerPic%(201) DIM SHARED PlayerPicMask%(201) DEF SEG = VARSEG(PlayerPic%(0)) BLOAD "player.bsv", VARPTR(PlayerPic%(0)) DEF SEG = VARSEG(PlayerPicMask%(0)) BLOAD "pmask.bsv", VARPTR(PlayerPicMask%(0)) SCREEN 13 LINE (0, 0)-(319, 199), 1, BF '--- This is the important part: --- PUT (100, 100), PlayerPicMask%, AND PUT (100, 100), PlayerPic%, OR '----------------------------------- That should be it, tada! Hope this tutorial helps. If you need more help, feel free to email me with the address above.