Jonathan's advanced graphics tutorial

1. An advanced breakdown of graphic screen modes
A. Foreword
B. SCREEN 7
C. SCREEN 8
D. SCREEN 9
E. SCREEN 12
F. SCREEN 13
G. A note on SVGA programming
2. Pages for SCREENs 7, 8, and 9
A. What are pages, and why don't SCREENs 12 and 13 have them?
B. Why would I want to use them?
C. How do I use them?
D. Can I create more pages?
3. Mouse support
A. Where are the commands and functions for a mouse?
B. Mouse basics
C. Graphics with the mouse
D. Useing the mouse in your programs
4. Sprites
A. What are sprites?
B. Sprite basics
C. Palette and Sprites
D. Advanced sprite techniques
E. Sprites and the mouse
5. Tutorial information
A. Contact information
B. Version history
C. FAQ (none yet)

This work is protected under copyright law (2003).

1. An advanced breakdown of graphic screen modes

A. Foreword

I know there are more screen modes than I am listing, but I am only listing notable screen modes. Unlisted screen modes are generally worse than other screen modes offering no special benifeits. Since virtually all computers now support all of these screen modes, there is no need to be concerned about compatibility. Size is in pixels. Colors is the number of colors. Attributes is the number of possible color definitions for a color. Text is like size, but measured by letters. Pages are extra invisible graphics areas (see 2.A.). Square is determined by drawing a square on the screen by pixels and seeing if the shape that basic draws appears to be a square. Full-screen is determined by drawing a rectangle on the screen that is the maximum size of the screen and seeing if it covers most of the screen.

B. SCREEN 7
Size: 320x200
Colors: 16
Attributes: 16
Text: 40x25
Pages: 7
Square: yes
Full-screen: yes
Most notable feature: Has the most pages among notable SCREEN modes.

SCREEN 7 is my favorite for most programming. It lacks a high resolution or lots of color, but it has more pages than any other SCREEN mode (see 2.A.). In my view, this is the best screen mode for makeing games as it is very easy to use and if worked with correctly, has no flicker (see 2.B. and 2.C.). The only downside is that it is not good for viewing pictures wit lots of color or drawings that have a lot of detail.

C. SCREEN 8

Size: 640x200
Colors: 16
Attributes: 16
Text: 80x25
Pages: 3
Square: no
Full-screen: yes
Most notable feature: More resolution than SCREEN 7 at half the pages.

I have never really used SCREEN 8 as it is not square. Generally, if I need higher resolution, I would use either SCREEN 9 or SCREEN 12. This SCREEN mode, however, does support anti-flicker and is therefore suitable for games.

D. SCREEN 9

Size: 640x350
Colors: 64
Attributes: 16
Text: 80x25 or 80x43 (See WIDTH command in QBasic)
Pages: 1
Square: yes
Full-screen: no
Most notable feature: Highest resolution with pages.
This SCREEN mode is suitable for games at the cost of speed. It does support anti-flicker, but it has no backup pages, so all graphics would have to be constantly redrawn. Having 64 colors means you can define a transparent color without dropping a basic color and you can also have animated graphics by color (see 4.C.). Advanced techniques could make this SCREEN mode the best for games, but not beeing full-screen might bother some people.

E. Screen 12

Size: 640x480
Colors: 16
Attributes: 262,144
Text: 80x30 or 80x60
Pages: 0
Square: yes
Full-screen: yes
Most notable feature: Highest resolution and most text.

I do not forsee any good games made in this screen mode. It does not support anti-flicker and has absolutely no backup pages. The only use I have ever found for it is showing the graphs of functions such as f(x) = x ^ 3.

F. Screen 13

Size: 320x200
Colors: 256
Attributes: 262,144
Text: 40x25
Pages: 0
Square: yes
Full-screen: yes
Most notable feature: Has the most colors.

Many would call this the best SCREEN mode based on having 256 colors that can be defined one of 262,144 attributes. There are only two problems with this SCREEN mode: first, it is low resolution, and second, it has no backup pages or anti-flicker support. I used to use this screen mode a lot for everything, but then I descovered pages. A good use for this screen mode is for displaying pictures. I have seen a program once that added pages to this mode, but four pages was enough to fill up all of the available memory for variables.

G. A note on SVGA programming

Since each of these SCREEN modes have their obvious limitations, some talented people have written some assembly code that allowed QBasic users to create SVGA graphics. Basically, an advantage is that you can have the colors of SCREEN 13, the resolution of SCREEN 12, and the pages of SCREEN 7 all at once. This is really good for games; however, all forms of SVGA programming are not truely QBasic and therefore have problems of their own. First, compatibility is not guarenteed. Second, many require that you load a special library with QBasic. Third, the commands that come with QBasic won't work. Fourth, some low quality versions are slow. Fifth, there are many versions, so the coding can look different for each one. Finally, not all QBasic drawing commands have a mirror in the SVGA programming in all SVGA versions. To the best of my knowledge, the best SVGA package is FUTURE SVGA, or something like that. I have never gotten past watching the demo, but as far as I can tell, it has mirror commands and functions for each of QBasic's drawing commands and functions, some extra drawing commands and functions (especially with sprites), 3d support (lacks texturing though), and built in mouse support. If you are early into learning graphics, you may want to look into this before memorizing all of the QBasic commands and syntax. FUTURE SVGA also supports screen resolutions greater than that of SCREEN 12.

2. Pages for SCREENs 7, 8, and 9

A. What are pages, and why don't SCREENs 12 and 13 have them?

Pages are simply small blocks of memory on your video card that are large enough to hold all of the information of all the pixels that would appear in the screen mode of your choice. When you use the SCREEN command, QBasic divides the video memory into pages. Since QBasic is an old language and was programmed around the time 1MB video cards would be unimaginably expensive, QBasic only uses 256kB of the video memory. SVGA programs have support code (written in ASSEMBLER) that helps use the rest of the memory. SCREEN 12 and SCREEN 13 have page sizes that are equal to 256kB or are greater than 128kB (or half of the video memory); therefore, they don't have pages because there isn't enough space to create a page.

B. Why would I want to use them?

The main use for pages is to make the screen look cleaner and to reduce flicker. Flicker is what happens mainly when you constanly clear the screen and redraw the graphics again. An example of flicker can be demonstrated through the following simple program:

SCREEN 7
FOR X% = 0 to 309
CLS
LINE (X%,0)-(X%+10,10), 15, BF
NEXT X%
END

When you run this program, you will be annoyed by the flashing of the box as it moves across the screen; in fact, really fast computers might make the box nearly invisible. Now try running the following program.

SCREEN 7, , 1, 0
FOR X% = 0 TO 309
CLS
LINE (X%, 0)-(X%+10,10),15, BF
WAIT &H3DA, 8
PCOPY 1, 0
NEXT X%
END

There should have been two things you should have noticed by running the program. The first is quite obvious: You can see the box, and it looks smooth. The other is slightly less noticable: The program runs slightly slower. I'll explain why it is slower in 2.C.

Another use for pages is displaying large graphics or multiple graphics simutaneously. For this example, lets say you wanted QBasic to make your screen look like it has static. A simple way to do this is to use the folowing program:

SCREEN 7
DO
FOR X% = 0 TO 319
FOR Y% = 0 TO 199
PSET (X%,Y%), INT(RND*16)
NEXT Y%
NEXT X%
LOOP WHILE INKEY$ = "" 'loop while no keys are pressed
END

This looks somewhat decent, but you should be able to see a line that craws from left to right over and over again.

Pages are able to get rid of that line by useing the modified code below:

SCREEN 7, , 1, 0
FOR X% = 0 TO 319
FOR Y% = 0 TO 199
PSET (X%,Y%), INT(RND*16)
NEXT Y%
NEXT X%
WAIT &H3DA, 8
PCOPY 1, 0
LOOP WHILE INKEY$ = ""
END

Here, too, you can see that the second program is slightly slower; however, the line is gone.
There are other uses for pages, but many are too lengthy to explain here, but this should give you an idea what you can do with them.

C. How do I use them?

Pages are very simple to use, as you can see from the previous examples, the use of pages only added some extra paramaters to the SCREEN command an two extra lines of code. To start with, I'll explain the extra paramaters first. You already know what the first number is, that is the screen mode number (for pages, it can be 7, 8, or 9). The second parameter is not used in any of the three screen modes, so leave it blank. I like to call the thrid paramater your work page number and the fourth your view page number (QBasic calls them apage and vpage respectively). When all paramaters are obmitted (like just calling SCREEN 7), the apage and vpage are set to 0 by default. Pages are numbered in a sequence starting with 0, the default page. The view page, or vpage, is the page that is shown to the user, the work page, or apage, is the page that all of QBasic's drawing commands draw to. When both apage and vpage are the same, anytime you use a drawing command, the user sees its result immedeatly, like in this sample program:

SCREEN 7, , 0, 0 'same as SCREEN 7
LINE (0,0)-(319, 199), 15
END

When apage and vpage are different, the user doesn't immedeatly see the result, as in the following program:

SCREEN 7, , 1, 0
LINE (0,0)-(319, 199), 15
END

You should notice that no line seems to be drawn; however, it was drawn, but it was drawn to page 1 instead of page 0, which is the page the user is viewing. I shouldn't have to tell you, but the user can only view one page at a time. So now you are probably asking yourself, how do I see the line I drew on a completly different screen? The best way is to copy the data from page 1 to page 0. This is easily acomplished by the PCOPY command. PCOPY is easy to use, as it only has two paramaters, source page and destination page, so to view the line in the second example, you would just add PCOPY 1, 0 before END. This tells QBasic to copy the information on page 1 to page 0, which the user is viewing. So any time you want to let the user view the graphics drawn, you just copy the apage to the vpage.

Now you might have noticed that I haven't yet mentioned the WAIT command used in the previous section, and that I didn't use it in the second example in this section. You may think that it is just a useless pice of code as it seems to have no effect on the examples; however, this is not true. Knowing how the wait command benefits the program requires a simple understanding of how a monitor works. A monitor works by shooting a stream of charged particles at the screen which charges the screen and causes it to glow for a short while. This stream is very narrow and sweeps quickly across the screen, moves down a line and sweeps again untill it reaches the bottom, at which time it returns to the top and starts again. All the WAIT command is for is to tell basic to wait until the stream is in the top left position and is ready for a new page to display, this is why programs that use anti-flicker techniques run slightly slower. When you don't use the WAIT command, the stream will start drawing the new page even when it is part of the way through drawing the previous page causing the top half of the screen to look like the previous page and the bottom half of the page to look like the current page untill it starts over again. This mixed page lasts for a fraction of a second, but it is just enough to annoy someone when the pages greatly contrast each other (for instance, quickly switching between a solid white and a solid black page). Fast and slow computers alike will have this problem, as monitors run close to the same speed. If you look at your monitor settings, the number of htz is how many times the stream sweeps the screen. I have made an example program to demonstrate the purpose of the WAIT comand. I do not suggest staring at the following program for very long while it is running.

'CAUTION! This program is highly capable of makeing someone sick!
SCREEN 7, , 1, 0
PAINT (0,0), 15
PRINT "PRESS ANY KEY TO START USEING THE WAIT COMMAND."
SCREEN 7, , 2, 0 'notice that I'm useing two pages in this example
PRINT "PRESS ANY KEY TO START USEING THE WAIT COMMAND."
DO
PCOPY 1, 0 'display the first page
PCOPY 2, 0 'then display the second page
LOOP WHILE INKEY$ = ""
SCREEN 7, , 1, 0 'redraw the first page
CLS
PAINT (0,0), 15
PRINT "Notice the difference. Press any key to quit."
SCREEN 7, , 2, 0 'redraw the second page
CLS
PRINT "Notice the difference. Press any key to quit."
DO
WAIT &H3DA, 8
PCOPY 1, 0
WAIT &H3DA, 8
PCOPY 2, 0
LOOP WHILE INKEY$ = ""
END

If you didn't fall over backwards sick when you ran this, you will notice that that after you hit a key once, the screen looks better (other than it is still flashing).

The parameters for WAIT work only for screen mode 7, so it is not necessary to change the paramaters unless you intend on useing a different sreen mode. Besides, I don't know what might happen if you change the paramaters. Don't ask me for paramaters for other screen modes, I don't know them.

D. Can I create more pages?

No, when you use the SCREEN command, QBasic automatically creates the most pages that can fit in 256kB of video memory. However, you can use the GET and PUT commands to simulate extra pages in SCREENs 7, 8, and 9 at the cost of variable memory. You would have to first make arrays that could hold the entire page, then GET the work page into a variable, that would be page 1. Make a second variable, GET the work page, and that would be page 2. When you want to draw to a page, GET the previous page, PUT the page you want to work on, use PCOPY to display the results, and you are done. Look up the GET and PUT commands in the QBasic help index for how to use them. I may eventually make a program that demonstrates this, but I don't feel that it is necessary unless people ask me to.

3. Mouse support

A. Where are the commands and functions for a mouse?

QBasic does not have commands that support the mouse. Instead, you have to use a support program to gain the use of the mouse. Most support programs make use of assembly level or machine level code that can add functions to QBasic. For the purpose of this tutorial, I will refer to useing the program Gmouse.bas. You need to download it to be able to make full use of this tutorial.

B. Mouse basics

When you first open GMouse.bas, you will notice that the first few lines look like this:

DECLARE SUB UPDATEMOUSE (AX%, EX%)
DECLARE SUB GETMOUSE ()
DECLARE SUB PUTMOUSE ()
DECLARE SUB SHOWMOUSE ()
DECLARE SUB HIDEMOUSE ()

These lines tell QBasic that there are new commands added that you can use. From here you can tell that there are five new commands, and only the first one requires paramaters. I will explain how to use these later. From there, there are several DIM and COMMON statements before UPDATEMOUSE is called. These DIM and COMMON statements create vars for different purposes that the subs use to communicate with. There are two calls to UPDATEMOUSE. The first loads driver information into memory, the second gets the initial coordinates of the mouse. The line that follows that has several definitions of variables are used for mostly for replacing the background when the mouse moves. FORCED% lets SHOWMOUSE know that it needs to draw the mouse the first time it is called, even if it doesn't move.
The four lines of data is the actual machine code that is used when you call the mouse functions. This data is very important, do not change or delete it if you want to have mouse support. Also, make sure that the first UPDATEMOUSE call is made before any RESTORE or READ statements and make sure that the four lines of mouse data are at the top of all data in you program. If you tried running the program, then you probably noticed that nothing happened. This is because this particular program is designed as a template that you start programming with. It initialises the mouse, but does nothing beyond that. The first thing you need to do to get GMOUSE to work, is to choose a screen mode you want to use it with. GMOUSE is compatible with all screen modes that support graphics. For this tutorial, I will use SCREEN 12 because it has the highest resolution. If you choose to use other screen modes, the you need to make changes to two of the subs in GMouse.bas. First, at the bottom of UPDATEMOUSE, you will notice a line that states "ENABLE THE BELOW LINE FOR SCREEN MODES 7 AND 13." If you choose to use either of the two screen modes, delete the appostrophe before MX%. The other change you need to make is in GETMOUSE. There you will find two variables: SCREENX% and SCREENY%. there are reminders that tell you what to set the values to. If you need screen resolution information, you can refer to section 1 in this tutorial. Insert the SCREEN command before DATA and after FORCED% = 1. You will also want to put END before DATA as well just to make the code seem a little cleaner. After selecting your screen mode, you need to then draw the background you want the mouse to move over. For this tutorial, I am just going to change the screen color from black to grey. I just put PAINT (0,0), 7 after my SCREEN statement to change the color of the screen. After the background is drawn, you need to call GETMOUSE. GETMOUSE copies a piece of the background that the mouse will be drawn over so that when the mouse needs to dissappear, PUTMOUSE can replace the background correctly. Now that the background is set up correctly, we need to set up a loop that will update the mouse on the screen. The simplest loop is as follows:

DO
SHOWMOUSE
LOOP WHILE INKEY$ = ""

Doesn't look hard, does it? I made this process as simple as possible. At this point, you are able to run it. Be sure of one thing though: Press almost any key on the keyboard to end the program, do not use Ctrl + Break to quit the program. If you use the break, the next time you run the program, the mouse will not be able to go all the way up or left. To correct this problem if it happens, just save your work, quit QBasic, restart QBasic, and then load your program. It is very handy to make sure you have a way to exit the program by keyboard when working with the mouse so you don't have to constantly restart QBasic. That is the reason for the WHILE INKEY$ = "".
You probably noticed that this program doesn't do much else, clicking the mouse buttons does nothing either. Don't worry, you just haven't told QBasic what to do with the mouse. The next two sections will describe how to do more with the mouse.

C. Graphics with the mouse

There isn't much to drawing with the mouse on the screen. First call PUTMOUSE to replace the background, make the changes you want to the background, call GETMOUSE to get the new background, set FORCED% = 1 and then call SHOWMOUSE to get the cursor to reappear. I would like to point out something about GMouse.bas in this section. The mouse cursor is not changeable at this point. I hope in the future to have the option to change mouse cursors, but I have not yet had the time to make the changes.

D. Useing the mouse in your programs

There isn't much to useing the mouse. All you need to know is what the following variables represent:

MX% = the X coordinate of the mouse
MY% = the Y coordinate of the mouse
LB% = the status of the left mouse button
RB% = the status of the right mouse button
MB% = the status of the middle mouse button
OMX% = the previous X coordinate
OMY% = the previous Y coordinate
OML% = the previous status of the left mouse button
OMR% = the previous status of the right mouse button
OMM% = the previous status of the middle mouse button

If you want your program to do something when a mouse button is pressed, just use something like this:

IF LB% = DOWN THEN PRINT "THE LEFT BUTTON IS DOWN"

Lets say for instance you wanted to have the program quit when a user clicks inside of a square. Lets make the background grey and the square red. You can use the program from section 3.B. to start with.
On the background, after painting it, insert LINE (10,10)-(30,30), 4, BF to draw a small red square on the screen.
To make the program quit when you click on the square, you first need to know if the mouse is in the box when the left mouse button is clicked. To test this, use this line:

INBOX% = (MX% >= 10 AND MX% <= 30) AND (MY% >= 10 AND MY% <= 30)

This line needs to come after SHOWMOUSE. To exit the program, you need to test to see if the mouse is in the box and that the button is down. Use the following line:

IF INBOX% AND LB% = DOWN THEN EXIT DO

Run the program and you will be able to exit by clicking the box. Simple, isn't it. By the way, HIDEMOUSE works the same as SHOWMOUSE, but the cursor is not drawn. This is handy when you want to know where the mouse is, but you don't want the cursor on the screen. Here are a few simple challenges you could try yourself to get oriented with programming with the mouse:

1. Make the box change color when the mouse moves over it. Hint: you will need to test the location of the mouse, but not the status of the mouse button when redrawing the box.

2. Make the box move around the screen while you try to click it. Hint: the coordinates you test for will have to change with the box.

3. Make a program that draws lines like in paintbrush. You need not have the lines able to change color, just a black screen and white lines are simple enough for now. Hint: After the mouse is clicked, keep redefining the end point of the line untill LB% = UP. Then, wait untill LB% = DOWN again before drawing a second line.

4. Make a program with multiple boxes you can click on. Each with a different action. For instance, make the first box use the BEEP command, the second play a short song using the PLAY command, and have a third quit the program. Hint: You will have to define seperate INBOX% variables for each box like INBOX1%, INBOX2%, and INBOX3%.

5. Expand on number 4. Make a graphical keyboard that plays musical notes when the mouse clicks on them. Hint: The white keys are not rectangle, so you will have to have a more complicated test to see if it is on a white key, try to figure this out on your own. To have more fun, you could also make the keys change color when the mouse is clicking on them.

If you get stuck trying any of these, I will be glad to help you debug your program; however, I would like to have seen that you made an effort first.
Created on 12/14/03.