Hi folks! Nice to see ya this time. Recovered from the boredom of linked list? Yep! Now, I'm not going to give theories about linked list, but now we go to practical matters. One interesting thing to add to our programs is GRAPHICS! Yes! After learning graphics, you should be able to bring your games into life. If you did any challenge in previous lessons like RPG games or Pac-Man, you can now bring your dream come true. Real graphics!
Borland Pascal has a nice unit to deal graphics with. That is GRAPH.TPU.
I assume you all have Borland or Turbo Pascal 7.0. If you just have Turbo
Pascal 5.0 or 6.0, you may modify the source a bit. I also assume you all
have VGA graphic cards, at least with memory of 256 KB. Check also the
file EGAVGA.BGI before continuing. All font files may be helpful
when you make programs that needs a lot of fonts. The fonts file are in
*.CHR extension. So, before you go on, you can step back and check
whether the files are exist or not. If you don't have one, your version
of Borland or Turbo Pascal is not complete!
Of course graphics! :-) Unfortunately Borland gives us the 16 colors of VGA graphics. That's OK. Later we would learn 256 as well. This BGI unit is easy to use. You don't even need to fiddle with the inner things about how it works. Nice! Don't be too disappointed. This lesson is intended to be the basic things before you go even higher!
The only resolution I'll discuss here is 640x480. That's the highest possible standard BGI can do. Oh well... However, if you do a very clever drawing and color use, you can trick users as if your games have at least 256 colors! If you don't believe me, take a look of Romance of the Three Kingdoms IV and V. Koei manufacture it. They use very clever graphics. I first think that they used 256 colors. Surprisingly enough, they only use 16 colors! WOW! How'd I know? If you don't believe me, take a look at it. By mentioning this, I'm not advertising the Koei product. I'm just sort of astonished of their expertise in using colors.
Ready to begin? Yeah! :-)
The first thing to do before you could bring graphics to life is initializing the driver. Yeah, you expert programer... say we must initialize the graphics card. That's later. In BGI, we don't need to be worried about that. Just initialize the BGI driver and you're set.
Then, before all thing's over, you need to destroy the screen. Yes!
That's the rule. Don't ask me why. The following excerpt will show you
the initialization and destroy part:
uses crt, graph; procedure init; var gd, gm : integer; begin gd:=VGA; gm:=VGAHi; initgraph(gd, gm, '.\BGI'); gd:=graphresult; if gd<>grOK then begin writeln('Error in initializing graphic card! The error is'); writeln(grapherrormsg(gd)); halt; end; end; procedure destroy; begin closegraph; writeln('Good bye!'); end; begin init; readkey; { Turbo Pascal 5.0 or 6.0 must change this to c:=readkey; } { with c is a char variable } destroy; end.
Let's discuss the initialization part first. The main thing in init procedure is initgraph. It accepts three parameters. The first two is graphic driver and graphic mode. Graphic driver is VGA and graphic mode is VGAHi (640x480x16). The third parameter is the directory where the driver, EGAVGA.BGI, is located. I assume it is located under BGI directory. Of course you can change the directory to suit your need.
After initgraph, we need to detect whether it has successfully changed into graphic screen or not. This value is stored inside the graph unit. Fortunately, we can invoke the function graphresult to get the value. But, graphresult will always reset the value after we call it. So, we'd like to store the graph result value into a variable. Here, we use gd, which is no longer used after initgraph. If the error emerges -- that is, gd is not grOK --, we need to say the error. The error message can be retrieved by using grapherrormsg. Of course we need to pass gd as the parameter. After telling what's the error, we quit by using halt.
Then the destroy part. The essence is only closegraph. After you closegraph, the screen will be restored. Usually back to text mode if text mode was the last mode. Here, you can say good bye message or so.
Actually, the graphic routines occur between the init and destroy.
I put readkey there. Just go to graphics screen, wait for a key, then back
to text (or last) mode, then quits.
Now put this line just before readkey, then run it again.
line (0,0,639,479);
You'll see a diagonal white line accross the screen, right? Now add setcolor(10); just before the line statement, then run it again. Now, the line turns green.
OK, before we go on, I need to explain that the screen has the dimension of 640x480. The top-left corner is (0,0) and the lower-right is (639,479). Try anything across this boundary, and this has no effect. All things have been clipped automatically by BGI drivers.
Try the rectangle, circle, ellipse, fillellipse,
arc, sector, bar, and so on. They will draw
things on the screen. Try it. If you are confused or don't know how to
use it, use Borland Pascal help.
Unlike text mode, we can not use write or writeln
to write something on the screen. Instead, we use outtext and
outtextxy. The difference between them is that outtextxy
employs the x and y to output the text and outtext does not. Try
adding these lines:
outtext('You are great!');
outtextxy(100,150,'You are very great!');
If you are bored to see the very same font, you can change fonts. First, make sure that you have font files exist. It is usually has the extension CHR. Try looking for TRIP.CHR, LITT.CHR, SANS.CHR, and GOTH.CHR. Are they in BGI directory? Yes? That's great!
Now, put this line just above the outtext or outtextxy
statement:
settextstyle(1,0,4);
Settextstyle takes three parameters. The first parameter is the font type. Try changing it from 0 to 9. The second is the direction, 0 for horizontal and 1 for vertical. The last parameter is font size, ranges from 1 to 10. All parameters are in word.
Other command is settextjustify. It modifies the justification
of your text. It takes two parameters. The first is for horizontal justification
and the other is for vertical justification. Try these lines:
rectangle(200,20, 400,100); settextjustify(0,2); outtextxy(320,20,'Top left justification'); settextjustify(2,2); outtextxy(320,40,'Top right justification'); settextjustify(1,2); outtextxy(320,60,'Top center justification');
Try modifying the second parameter to 0 and 1.
You can modify the size of the font in another way, using setusercharsize.
It takes four parameters, say it a, b, c, and d. The text will be enlarged
a/b times horizontally and c/d times vertically. Try this:
setusercharsize(2,1,1,1); outtextxy(100,100,'Twice as fat'); setusercharsize(1,1,2,1); outtextxy(100,140,'Twice as tall');
You can also apply colors for your text.
You can also fill any region using floodfill. But the first thing to do before filling any regions, you need to set up the fill style. This is done through setfillstyle. Setfillstyle takes two parameters. The first is pattern number (0 to 12) the second is fill color. Note that fill color is different then the color set by setcolor!
After setting up the fill style, you can apply floodfill. The
floodfill needs three parameters. The first two is the coordinate
(X,Y) specifying where we want to start filling. The third is border color.
Means that the fill is stopped whenever it reaches the border that is specified
in the third parameter. Try this:
setcolor(11); rectangle(100,100,300,200); setfillstyle(6,5); floodfill(150,150,11); { Fill the rectangle }
You can also use bar to draw filled rectangles. Custom pattern and line pattern will be discussed in the next chapter.
Polygons are easily made in Borland Pascal. Here's how to draw it: use drawpoly. Drawpoly takes two parameters: the first is the number of vertex. The other is the array of coordinates (X,Y). What is vertex any way? It is the total end points of a shape plus 1. So, triangle has 4 vertex, that is, 3+1. Rectangles has 5 vertex, 4+1. The coordinates are in integer or word. Look at this excerpt. Add this lines in constant declaration.
const shape : array[1..10] of word = ( 100,150 , 130,110 , 150,160, 140,200 , 100,150 );
Then add this:
drawpoly(5,shape);
It should draw a strange 4-points shape. Notice that the first and
the last coordinate of the polygon is the same. Otherwise, it wouldn't
be a polygon, just series of lines. If you'd like to have a filled polygon,
use fillpoly instead of drawpoly. Of course you need
to set the setfillstyle first.
In graphics screen, you cannot clear screen using clrscr. Use cleardevice instead.
You can clip graphics screen as if you are in text mode. However, you can no longer employ window command. Now, it is replaced by setviewport. The parameters is essentially the same, except now the coordinates are in graphics coordinate. Try this:
setviewport(100,100,500,400);
line(0,0,639,479);
Notice that the line is now clipped. Try removing the setviewport command and see what happens. Resetting viewport is done by this, making viewport as big as the graphic screen:
setviewport(0,0,639,479);
Pixel, Palette and RGB Value
You can draw a single dot on the screen. Each dot on the screen is called pixel. You can employ putpixel. It takes three parameters. The first two are for the coordinates, X and Y. The third is for the color. This means that putpixel can be colored differently from setcolor. Try this: putpixel(0,0,14); It draws a yellow dot on the top-left of the screen.
As the complement of putpixel, getpixel function returns the color value of a pixel. It takes two arguments, X and Y.
You need to know that the colors in the screen are made up from three components: Red, Green, and Blue. This system is called RGB system. There are many other system, but the main thing is that you understand this. Even yellow or white is composed from Red, Green, and Blue values. If we mix red and green, we'd get yellow right? Remember the color mixing experiments in the high school? Yeah! I know you're smart! :-)
Now, Pascal provide us a tool to modify the red, green, and blue value of each color we want. We use setRGBpalette. It takes four parameters. The first is the palette number we want to modify. The rest are for red, green, and blue value respectively. However, we need to be cautious. Color number is NOT the same as palette number. Color number is the numbers you have learnt in the first lesson, using textcolor and textbackground. The palette number is pretty the same as color number, but quite different.
Palette number for color 0 to 7 is exactly the same except for the color
6. Color 6 takes the palette number 20. The color 8 to 15 takes palette
number 56 to 63. Confused? Here's the clue: If you want to modify dark
blue color, that is color 1, you just do this:
setrgbpalette(1, 30,20,10);
Because the palette number and the color number is the same, you can
put 1 for the first parameter. But, if you want to modify the color 14,
which is originally yellow, you can't put 14 as the first parameter. You
put 62 instead. It's all because the palette number for the color 14 is
62. Clear?
However, you can re-arrange the palette number for the color number specified. This is done through setpalette. It takes two parameters, the first is the color number, then the second is the palette number.
What is exactly the palette? The screen uses 16 colors, color 0 through 15. The palette is the real color. The analogy is that you have 16 pens. The pens can be assigned with colors. That color is the palette. Suppose pen 1 is assigned as dark blue as the default. If you don't like the pen 1 has the color dark blue, you can then assign it with different color. That's the analogy.
The screen has 64 palette, but you can only use 16 colors simultaneously.
Using the analogy I've mentioned above, you should now be able to tell
what exactly the palette is.
The last thing I would like to explain here is getimage and putimage. You can store a region of drawing into a buffer and later be put in somewhere else. In this part, you need to have a firm grip of pointers. It's all because the buffer is an untyped pointer. Yeah, you can use array too, but that's not practical.
Before you can get an image, you need to know the size of an image. It is done because we need to know the size the pointer will be. This calculation is done by the function imagesize. It takes four parameters (x1,y1,x2,y2). As usual, (x1,y1) denotes the top left corner of the region and (x2,y2) is the lower-right corner. It returns the size in bytes.
The next step is reserve the buffer using getmem. Then we can apply getimage. To see the result, put the image somewhere using putimage. Don't forget to freemem the buffer before quitting.
Don't apply getimage and putimage on an empty screen.
All you see is black. :-) Draw something first. Look at this excerpt:
var p : pointer; s : word; : : setcolor(11); { Draw something first } line(0,0,639,479); setcolor(14); rectangle(10,10, 50,30); s:=imagesize(0,0,100,100); { Get to know the size } getmem(p,s); { Reserve the buffer } getimage(0,0,100,100,p^); { Get the image! } putimage(300,100,p^,0); { Put it somewhere else } freemem(p,s); { Free the buffer } readkey;
Now you're understand :-). Hey, what's the last parameter of putimage? Why did you put 0 in it? Well, that's a Bitblt constant. 0 stands for copyput. That means the image is put on (300,100) from the buffer p as is, no need to do bitblt operations.
What's bitblt operation anyway? That's sort of logic operations done
to the image before being put on the screen. The operations can be COPY,
AND, OR, XOR, and NOT. Try changing
the number 0 to other number.
Yeah, you finally made it. I hope this chapter will be a fun for you. Remember, you cannot use read and readln in graphics. You must make one instead. Remember Window's input box? Try make one.
That's all folks! Not quite long, right? Shall we go to the quiz or the next lesson?
Back to main page
Back to Pascal Tutorial Lesson 2 contents
To the quiz
To Chapter 7 about BGI Graphics part 2
My page of programming link
Contact me here
By: Roby Joehanes, © 1997, 2000