home *** CD-ROM | disk | FTP | other *** search
/ HomeWare 14 / HOMEWARE14.bin / prog / pcgpe10.arj / TUT3.TXT < prev    next >
Text File  |  1994-05-05  |  21KB  |  625 lines

  1.                    ╒═══════════════════════════════╕
  2.                    │         W E L C O M E         │
  3.                    │  To the VGA Trainer Program   │ │
  4.                    │              By               │ │
  5.                    │      DENTHOR of ASPHYXIA      │ │ │
  6.                    ╘═══════════════════════════════╛ │ │
  7.                      ────────────────────────────────┘ │
  8.                        ────────────────────────────────┘
  9.  
  10.                            --==[ PART 3 ]==--
  11.  
  12.  
  13.  
  14. ■ Introduction
  15.  
  16.  
  17.  
  18. Greetings! This is the third part of the VGA Trainer series! Sorry it 
  19. took so long to get out, but I had a running battle with the traffic
  20. department for three days to get my car registered, and then the MailBox
  21. went down. Ahh, well, life stinks. Anyway, today will do some things
  22. vital to most programs : Lines and circles.
  23.  
  24. Watch out for next week's part : Virtual screens. The easy way to
  25. eliminate flicker, "doubled sprites", and subjecting the user to watch
  26. you building your screen. Almost every ASPHYXIA demo has used a virtual
  27. screen (with the exception of the SilkyDemo), so this is one to watch out
  28. for. I will also show you how to put all of these loose procedures into
  29. units.
  30.  
  31. If you would like to contact me, or the team, there are many ways you 
  32. can do it : 1) Write a message to Grant Smith in private mail here on
  33.                   the Mailbox BBS.
  34.             2) Write a message here in the Programming conference here
  35.                   on the Mailbox (Preferred if you have a general
  36.                   programming query or problem others would benefit from)
  37.             3) Write to ASPHYXIA on the ASPHYXIA BBS.
  38.             4) Write to Denthor, Eze or Livewire on Connectix.
  39.             5) Write to :  Grant Smith
  40.                            P.O.Box 270 Kloof
  41.                            3640
  42.             6) Call me (Grant Smith) at 73 2129 (leave a message if you 
  43.                   call during varsity)
  44.                   
  45. NB : If you are a representative of a company or BBS, and want ASPHYXIA 
  46.        to do you a demo, leave mail to me; we can discuss it.
  47. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
  48.         quite lonely and want to meet/help out/exchange code with other demo
  49.         groups. What do you have to lose? Leave a message here and we can work
  50.         out how to transfer it. We really want to hear from you!
  51.  
  52.  
  53. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  54. ■  Circle Algorithim
  55.  
  56. You all know what a circle looks like. But how do you draw one on the
  57. computer?
  58.  
  59. You probably know circles drawn with the degrees at these points :
  60.  
  61.                                 0
  62.                               ▄█|█▄
  63.                              ███|███
  64.                         270 ----+---- 90
  65.                              ███|███
  66.                               ▀█|█▀
  67.                                180
  68.  
  69. Sorry about my ASCI ;-) ... anyway, Pascal doesn't work that way ... it
  70. works with radians instead of degrees. (You can convert radians to degrees,
  71. but I'm not going to go into that now. Note though that in pascal, the
  72. circle goes like this :
  73.  
  74.                                270
  75.                               ▄█|█▄
  76.                              ███|███
  77.                         180 ----+---- 0
  78.                              ███|███
  79.                               ▀█|█▀
  80.                                 90
  81.  
  82.  
  83. Even so, we can still use the famous equations to draw our circle ...
  84. (You derive the following by using the theorem of our good friend
  85. Pythagoras)
  86.                      Sin (deg) = Y/R
  87.                      Cos (deg) = X/R
  88. (This is standard 8(?) maths ... if you haven't reached that level yet,
  89. take this to your dad, or if you get stuck leave me a message and I'll
  90. do a bit of basic Trig with you. I aim to please ;-))
  91.  
  92. Where Y = your Y-coord
  93.       X = your X-coord
  94.       R = your radius (the size of your circle)
  95.       deg = the degree
  96.  
  97. To simplify matters, we rewrite the equation to get our X and Y values :
  98.  
  99.                      Y = R*Sin(deg)
  100.                      X = R*Cos(deg)
  101.  
  102. This obviousy is perfect for us, because it gives us our X and Y co-ords
  103. to put into our putpixel routine (see Part 1). Because the Sin and Cos
  104. functions return a Real value, we use a round function to transform it
  105. into an Integer.
  106.  
  107.      Procedure Circle (oX,oY,rad:integer;Col:Byte);
  108.      VAR deg:real;
  109.          X,Y:integer;
  110.      BEGIN
  111.        deg:=0;
  112.        repeat
  113.          X:=round(rad*COS (deg));
  114.          Y:=round(rad*sin (deg));
  115.          putpixel (x+ox,y+oy,Col);
  116.          deg:=deg+0.005;
  117.        until (deg>6.4);
  118.      END;
  119.  
  120. In the above example, the smaller the amount that deg is increased by,
  121. the closer the pixels in the circle will be, but the slower the procedure.
  122. 0.005 seem to be best for the 320x200 screen. NOTE : ASPHYXIA does not use
  123. this particular circle algorithm, ours is in assembly language, but this
  124. one should be fast enough for most. If it isn't, give us the stuff you are
  125. using it for and we'll give you ours.
  126.  
  127.  
  128. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  129. ■  Line algorithms
  130.  
  131. There are many ways to draw a line on the computer. I will describe one
  132. and give you two. (The second one you can figure out for yourselves; it
  133. is based on the first one but is faster)
  134.  
  135. The first thing you need to do is pass what you want the line to look
  136. like to your line procedure. What I have done is said that x1,y1 is the
  137. first point on the screen, and x2,y2 is the second point. We also pass the
  138. color to the procedure. (Remember the screens top left hand corner is (0,0);
  139. see Part 1)
  140.  
  141. Ie.            o  (X1,Y1)
  142.                 ooooooooo
  143.                          ooooooooo
  144.                                   oooooooo  (X2,Y2)
  145.  
  146. Again, sorry about my drawings ;-)
  147.  
  148. To find the length of the line, we say the following :
  149.  
  150.            XLength = ABS (x1-x2)
  151.            YLength = ABS (y1-y2)
  152.  
  153. The ABS function means that whatever the result, it will give you an
  154. absolute, or posotive, answer. At this stage I set a variable stating
  155. wheter the difference between the two x's are negative, zero or posotive.
  156. (I do the same for the y's) If the difference is zero, I just use a loop
  157. keeping the two with the zero difference posotive, then exit.
  158.  
  159. If neither the x's or y's have a zero difference, I calculate the X and Y
  160. slopes, using the following two equations :
  161.  
  162.            Xslope = Xlength / Ylength
  163.            Yslope = Ylength / Xlength
  164.  
  165. As you can see, the slopes are real numbers.
  166. NOTE : XSlope = 1 / YSlope
  167.  
  168. Now, there are two ways of drawing the lines :
  169.  
  170.            X = XSlope * Y
  171.            Y = YSlope * X
  172.  
  173. The question is, which one to use? if you use the wrong one, your line
  174. will look like this :
  175.  
  176.         o
  177.            o
  178.               o
  179.  
  180. Instead of this :
  181.  
  182.         ooo
  183.            ooo
  184.               ooo
  185.  
  186. Well, the solution is as follows :
  187.  
  188.                            *\``|``/*
  189.                            ***\|/***
  190.                            ----+----
  191.                            ***/|\***
  192.                            */``|``\*
  193.  
  194. If the slope angle is in the area of the stars (*) then use the first
  195. equation, if it is in the other section (`) then use the second one.
  196. What you do is you calculate the variable on the left hand side by
  197. putting the variable on the right hand side in a loop and solving. Below
  198. is our finished line routine :
  199.  
  200. Procedure Line (x1,y1,x2,y2:integer;col:byte);
  201. VAR x,y,xlength,ylength,dx,dy:integer;
  202.     xslope,yslope:real;
  203. BEGIN
  204.   xlength:=abs (x1-x2);
  205.   if (x1-x2)<0 then dx:=-1;
  206.   if (x1-x2)=0 then dx:=0;
  207.   if (x1-x2)>0 then dx:=+1;
  208.   ylength:=abs (y1-y2);
  209.   if (y1-y2)<0 then dy:=-1;
  210.   if (y1-y2)=0 then dy:=0;
  211.   if (y1-y2)>0 then dy:=+1;
  212.   if (dy=0) then BEGIN
  213.     if dx<0 then for x:=x1 to x2 do
  214.       putpixel (x,y1,col);
  215.     if dx>0 then for x:=x2 to x1 do
  216.       putpixel (x,y1,col);
  217.     exit;
  218.   END;
  219.   if (dx=0) then BEGIN
  220.     if dy<0 then for y:=y1 to y2 do
  221.       putpixel (x1,y,col);
  222.     if dy>0 then for y:=y2 to y1 do
  223.       putpixel (x1,y,col);
  224.     exit;
  225.   END;
  226.   xslope:=xlength/ylength;
  227.   yslope:=ylength/xlength;
  228.   if (yslope/xslope<1) and (yslope/xslope>-1) then BEGIN
  229.     if dx<0 then for x:=x1 to x2 do BEGIN
  230.                    y:= round (yslope*x);
  231.                    putpixel (x,y,col);
  232.                  END;
  233.     if dx>0 then for x:=x2 to x1 do BEGIN
  234.                    y:= round (yslope*x);
  235.                    putpixel (x,y,col);
  236.                  END;
  237.   END
  238.   ELSE
  239.   BEGIN
  240.     if dy<0 then for y:=y1 to y2 do BEGIN
  241.                    x:= round (xslope*y);
  242.                    putpixel (x,y,col);
  243.                  END;
  244.     if dy>0 then for y:=y2 to y1 do BEGIN
  245.                    x:= round (xslope*y);
  246.                    putpixel (x,y,col);
  247.                  END;
  248.   END;
  249. END;
  250.  
  251. Quite big, isn't it? Here is a much shorter way of doing much the same
  252. thing :
  253.  
  254. function sgn(a:real):integer;
  255. begin
  256.      if a>0 then sgn:=+1;
  257.      if a<0 then sgn:=-1;
  258.      if a=0 then sgn:=0;
  259. end;
  260.  
  261. procedure line(a,b,c,d,col:integer);
  262. var u,s,v,d1x,d1y,d2x,d2y,m,n:real;
  263.     i:integer;
  264. begin
  265.      u:= c - a;
  266.      v:= d - b;
  267.      d1x:= SGN(u);
  268.      d1y:= SGN(v);
  269.      d2x:= SGN(u);
  270.      d2y:= 0;
  271.      m:= ABS(u);
  272.      n := ABS(v);
  273.      IF NOT (M>N) then
  274.      BEGIN
  275.           d2x := 0 ;
  276.           d2y := SGN(v);
  277.           m := ABS(v);
  278.           n := ABS(u);
  279.      END;
  280.      s := INT(m / 2);
  281.      FOR i := 0 TO round(m) DO
  282.      BEGIN
  283.           putpixel(a,b,col);
  284.           s := s + n;
  285.           IF not (s<m) THEN
  286.           BEGIN
  287.                s := s - m;
  288.                a:= a +round(d1x);
  289.                b := b + round(d1y);
  290.           END
  291.           ELSE
  292.           BEGIN
  293.                a := a + round(d2x);
  294.                b := b + round(d2y);
  295.           END;
  296.      end;
  297. END;
  298.  
  299. This routine is very fast, and should meet almost all of your requirements
  300. (ASPHYXIA used it for quite a while before we made our new one.)
  301. In the end program, both the new line routine and the circle routine are
  302. tested. A few of the procedures of the first parts are also used.
  303.  
  304. Line and circle routines may seem like fairly trivial things, but they are
  305. a vital component of many programs, and you may like to look up other
  306. methods of drawing them in books in the library (I know that here at the
  307. varsity they have books for doing this kind of stuff all over the place)
  308. A good line routine to look out for is the Bressenhams line routine ...
  309. there is a Bressenhams circle routine too ... I have documentaiton for them
  310. if anybody is interested, they are by far some of the fastest routines
  311. you will use.
  312.  
  313. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  314. ■  In closing
  315.  
  316. Varsity has started again, so I am (shock) going to bed before three in
  317. the morning, so my quote this week wasn't written in the same wasted way
  318. my last weeks one was (For last week's one, I had gotten 8 hours sleep in
  319. 3 days, and thought up and wrote the quote at 2:23 am before I fell asleep.)
  320.  
  321.         [  "What does it do?" she asks.
  322.            "It's a computer," he replies.
  323.            "Yes, dear, but what does it do?"
  324.            "It ..er.. computes! It's a computer."
  325.            "What does it compute?"
  326.            "What? Er? Um. Numbers! Yes, numbers!" He smiles
  327.               worriedly.
  328.            "Why?"
  329.            "Why? Well ..um.. why?" He starts to sweat.
  330.            "I mean, is it just something to dust around, or does
  331.               it actually do something useful?"
  332.            "Um...you can call other computers with it!" Hope lights
  333.               up his eyes. "So you can get programs from other computers!"
  334.            "I see. Tell me, what do these programs do?"
  335.            "Do? I don't think I fol..."
  336.            "I see. They compute. Numbers. For no particular reason." He
  337.               withers under her gaze.
  338.            "Yes, but..."
  339.            She smiles, and he trails off, defeated. She takes another look
  340.                at the thing. "Although," she says, with a strange look in
  341.                her eyes. He looks up, an insane look of hope on his
  342.                face. "Does it come in pink?" she asks.
  343.                                                                            ]
  344.                                                      - Grant Smith
  345.                                                         Tue 27 July, 1993
  346.                                                          9:35 pm.
  347.  
  348. See you next time,
  349.     - Denthor
  350.  
  351.  
  352. ┌──────────────┬─────────────────────────────────────────────────────────────
  353. │ TUTPROG3.PAS │
  354. └──────────────┘
  355.  
  356. {$X+}
  357. USES crt;
  358.  
  359. CONST VGA = $a000;
  360.  
  361. VAR loop1:integer;
  362.     Pall : Array [1..199,1..3] of byte;
  363.       { This is our temporary pallette. We ony use colors 1 to 199, so we
  364.         only have variables for those ones. }
  365.  
  366. {──────────────────────────────────────────────────────────────────────────}
  367. Procedure SetMCGA;  { This procedure gets you into 320x200x256 mode. }
  368. BEGIN
  369.   asm
  370.      mov        ax,0013h
  371.      int        10h
  372.   end;
  373. END;
  374.  
  375.  
  376. {──────────────────────────────────────────────────────────────────────────}
  377. Procedure SetText;  { This procedure returns you to text mode.  }
  378. BEGIN
  379.   asm
  380.      mov        ax,0003h
  381.      int        10h
  382.   end;
  383. END;
  384.  
  385.  
  386. {──────────────────────────────────────────────────────────────────────────}
  387. Procedure Putpixel (X,Y : Integer; Col : Byte);
  388.   { This puts a pixel on the screen by writing directly to memory. }
  389. BEGIN
  390.   Mem [VGA:X+(Y*320)]:=Col;
  391. END;
  392.  
  393.  
  394. {──────────────────────────────────────────────────────────────────────────}
  395. procedure WaitRetrace; assembler;
  396. label
  397.   l1, l2;
  398. asm
  399.     mov dx,3DAh
  400. l1:
  401.     in al,dx
  402.     and al,08h
  403.     jnz l1
  404. l2:
  405.     in al,dx
  406.     and al,08h
  407.     jz  l2
  408. end;
  409.  
  410.  
  411. {──────────────────────────────────────────────────────────────────────────}
  412. Procedure Pal(ColorNo : Byte; R,G,B : Byte);
  413.   { This sets the Red, Green and Blue values of a certain color }
  414. Begin
  415.    Port[$3c8] := ColorNo;
  416.    Port[$3c9] := R;
  417.    Port[$3c9] := G;
  418.    Port[$3c9] := B;
  419. End;
  420.  
  421.  
  422. {──────────────────────────────────────────────────────────────────────────}
  423. Procedure Circle (X,Y,rad:integer;Col:Byte);
  424.   { This draws a circle with centre X,Y, with Rad as it's radius }
  425. VAR deg:real;
  426. BEGIN
  427.   deg:=0;
  428.   repeat
  429.     X:=round(rad*COS (deg));
  430.     Y:=round(rad*sin (deg));
  431.     putpixel (x+160,y+100,col);
  432.     deg:=deg+0.005;
  433.   until (deg>6.4);
  434. END;
  435.  
  436.  
  437. {──────────────────────────────────────────────────────────────────────────}
  438. Procedure Line2 (x1,y1,x2,y2:integer;col:byte);
  439.   { This draws a line from x1,y1 to x2,y2 using the first method }
  440. VAR x,y,xlength,ylength,dx,dy:integer;
  441.     xslope,yslope:real;
  442. BEGIN
  443.   xlength:=abs (x1-x2);
  444.   if (x1-x2)<0 then dx:=-1;
  445.   if (x1-x2)=0 then dx:=0;
  446.   if (x1-x2)>0 then dx:=+1;
  447.   ylength:=abs (y1-y2);
  448.   if (y1-y2)<0 then dy:=-1;
  449.   if (y1-y2)=0 then dy:=0;
  450.   if (y1-y2)>0 then dy:=+1;
  451.   if (dy=0) then BEGIN
  452.     if dx<0 then for x:=x1 to x2 do
  453.       putpixel (x,y1,col);
  454.     if dx>0 then for x:=x2 to x1 do
  455.       putpixel (x,y1,col);
  456.     exit;
  457.   END;
  458.   if (dx=0) then BEGIN
  459.     if dy<0 then for y:=y1 to y2 do
  460.       putpixel (x1,y,col);
  461.     if dy>0 then for y:=y2 to y1 do
  462.       putpixel (x1,y,col);
  463.     exit;
  464.   END;
  465.   xslope:=xlength/ylength;
  466.   yslope:=ylength/xlength;
  467.   if (yslope/xslope<1) and (yslope/xslope>-1) then BEGIN
  468.     if dx<0 then for x:=x1 to x2 do BEGIN
  469.                    y:= round (yslope*x);
  470.                    putpixel (x,y,col);
  471.                  END;
  472.     if dx>0 then for x:=x2 to x1 do BEGIN
  473.                    y:= round (yslope*x);
  474.                    putpixel (x,y,col);
  475.                  END;
  476.   END
  477.   ELSE
  478.   BEGIN
  479.     if dy<0 then for y:=y1 to y2 do BEGIN
  480.                    x:= round (xslope*y);
  481.                    putpixel (x,y,col);
  482.                  END;
  483.     if dy>0 then for y:=y2 to y1 do BEGIN
  484.                    x:= round (xslope*y);
  485.                    putpixel (x,y,col);
  486.                  END;
  487.   END;
  488. END;
  489.  
  490.  
  491. {──────────────────────────────────────────────────────────────────────────}
  492. procedure line(a,b,c,d,col:integer);
  493.   { This draws a line from x1,y1 to x2,y2 using the first method }
  494.  
  495.     function sgn(a:real):integer;
  496.     begin
  497.          if a>0 then sgn:=+1;
  498.          if a<0 then sgn:=-1;
  499.          if a=0 then sgn:=0;
  500.     end;
  501.  
  502. var u,s,v,d1x,d1y,d2x,d2y,m,n:real;
  503.     i:integer;
  504. begin
  505.      u:= c - a;
  506.      v:= d - b;
  507.      d1x:= SGN(u);
  508.      d1y:= SGN(v);
  509.      d2x:= SGN(u);
  510.      d2y:= 0;
  511.      m:= ABS(u);
  512.      n := ABS(v);
  513.      IF NOT (M>N) then
  514.      BEGIN
  515.           d2x := 0 ;
  516.           d2y := SGN(v);
  517.           m := ABS(v);
  518.           n := ABS(u);
  519.      END;
  520.      s := INT(m / 2);
  521.      FOR i := 0 TO round(m) DO
  522.      BEGIN
  523.           putpixel(a,b,col);
  524.           s := s + n;
  525.           IF not (s<m) THEN
  526.           BEGIN
  527.                s := s - m;
  528.                a:= a +round(d1x);
  529.                b := b + round(d1y);
  530.           END
  531.           ELSE
  532.           BEGIN
  533.                a := a + round(d2x);
  534.                b := b + round(d2y);
  535.           END;
  536.      end;
  537. END;
  538.  
  539.  
  540. {──────────────────────────────────────────────────────────────────────────}
  541. Procedure PalPlay;
  542.   { This procedure mucks about with our "virtual pallette", then shoves it
  543.     to screen. }
  544. Var Tmp : Array[1..3] of Byte;
  545.   { This is used as a "temporary color" in our pallette }
  546.     loop1 : Integer;
  547. BEGIN
  548.    Move(Pall[199],Tmp,3);
  549.      { This copies color 199 from our virtual pallette to the Tmp variable }
  550.    Move(Pall[1],Pall[2],198*3);
  551.      { This moves the entire virtual pallette up one color }
  552.    Move(Tmp,Pall[1],3);
  553.      { This copies the Tmp variable to the bottom of the virtual pallette }
  554.    WaitRetrace;
  555.    For loop1:=1 to 199 do
  556.      pal (loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]);
  557. END;
  558.  
  559.  
  560. BEGIN
  561.   ClrScr;
  562.   Writeln ('This sample program will test out our line and circle algorithms.');
  563.   Writeln ('In the first part, many circles will be draw creating (hopefully)');
  564.   Writeln ('a "tunnel" effect. I will the rotate the pallete to make it look');
  565.   Writeln ('nice. I will then draw some lines and rotate the pallette on them');
  566.   Writeln ('too. Note : I am using the slower (first) line algorithm (in');
  567.   Writeln ('procedure line2). Change it to Procedure Line and it will be using');
  568.   Writeln ('the second line routine. NB : For descriptions on how pallette works');
  569.   Writeln ('have a look at part two of this series; I won''t re-explain it here.');
  570.   Writeln;
  571.   Writeln ('Remember to send me any work you have done, I am most eager to help.');
  572.   Writeln; Writeln;
  573.   Writeln ('Hit any key to continue ...');
  574.   Readkey;
  575.   setmcga;
  576.  
  577.   For Loop1 := 1 to 199 do BEGIN
  578.     Pall[Loop1,1] := Loop1 mod 30+33;
  579.     Pall[Loop1,2] := 0;
  580.     Pall[Loop1,3] := 0;
  581.   END;
  582.        { This sets colors 1 to 199 to values between 33 to 63. The MOD
  583.          function gives you the remainder of a division, ie. 105 mod 10 = 5 }
  584.  
  585.    WaitRetrace;
  586.    For loop1:=1 to 199 do
  587.      pal (loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]);
  588.         { This sets the true pallette to variable Pall }
  589.  
  590.   for loop1:=1 to 90 do
  591.     circle (160,100,loop1,loop1);
  592.        { This draws 90 circles all with centres at 160,100; with increasing
  593.          radii and colors. }
  594.  
  595.   Repeat
  596.     PalPlay;
  597.   Until keypressed;
  598.   Readkey;
  599.  
  600.   for loop1:=1 to 199 do
  601.     line2 (0,1,319,loop1,loop1);   { *** Replace Line2 with Line to use the
  602.                                          second line algorithm *** }
  603.        { This draws 199 lines, all starting at 0,1 }
  604.  
  605.   Repeat
  606.     PalPlay;
  607.   Until keypressed;
  608.  
  609.   readkey;
  610.   SetText;
  611.   Writeln ('All done. Okay, so maybe it wasn''t a tunnel effect, but you get the');
  612.   Writeln ('general idea ;-) This concludes the third sample program in the ASPHYXIA');
  613.   Writeln ('Training series. You may reach DENTHOR under the name of GRANT SMITH');
  614.   Writeln ('on the MailBox BBS, or leave a message to ASPHYXIA on the ASPHYXIA BBS.');
  615.   Writeln ('Get the numbers from Roblist, or write to :');
  616.   Writeln ('             Grant Smith');
  617.   Writeln ('             P.O. Box 270');
  618.   Writeln ('             Kloof');
  619.   Writeln ('             3640');
  620.   Writeln ('I hope to hear from you soon!');
  621.   Writeln; Writeln;
  622.   Write   ('Hit any key to exit ...');
  623.   Readkey;
  624. END.
  625.