Graphics programming.

Normally, when you need a good and reliable graphics package, you go for SVGAlib. It's stable, fast and reasonably universal. But, svgalib was written for and in C. And I kind of don't like C. To put it mildly.
I'm not saying that C is a bad programming language. It's just not my kind of language since it gives too much freedom and almost no protection.

That's why I want to use Modula-2 in combination with the SVGAlib libraries. And Modula-2 offers a construct to do just that: the FOREIGN MODULE. There's an example of a foreign module in the IOport section.

Sources for the FOREIGN MODULEs.

Below are the source files that make up the current 'Vga MODULE'. The first part is in C, the second is the 'DEFINITION MODULE'.

#include <vga.h>

int   Initialize (void)
{
   if ( vga_init () == 0 )
     return 1;
   else
     return 0;
}

void  SetMode (int newmode)
{
   vga_setmode (newmode);
}

int   GetMode (void)
{
   return vga_getcurrentmode ();
}

int   MaxWidth (void)
{
   return vga_getxdim ();
}

int   MaxHeight (void)
{
   return vga_getydim ();
}

void  Clear (void)
{
   vga_clear ();
}

void  SetColour (int colour)
{
   vga_setcolor (colour);
}

void  SetEGAcolour (int colour)
{
   vga_setegacolor (colour);
}

void  SetRGB (int red, int green, int blue)
{
   vga_setrgbcolor (red, green, blue);
}

void   DrawLine (int x0, int y0, int dx, int dy)
{
   vga_drawline (x0, y0, x0 + dx, y0 + dy);
}

void   Plot (int x, int y)
{
   vga_drawpixel (x, y);
}

int    ThisColour (int x, int y)
{
   return vga_getpixel (x, y);
}

void   GetKey (char *ch)
{
   *ch = vga_getkey ();
}
   
These functions are SMALL and all they do is make an interface for Modula-2 to hook itself on. We also get the chance to rename the functions or even change the order and nature of the arguments. As you undoubtedly have seen... :o)

Compile with
gcc -c vga.c
What follows is the source of the 'DEFINITION MODULE', although it is now called a 'FOREIGN MODULE' to indicate that the 'IMPLEMENTATION' section is -not- in Modula-2.
FOREIGN MODULE Vga;


TYPE	EGAcolour  = (black, blue, green, cyan, red,    pink,  brown, white,
		       GREY, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE);


PROCEDURE Initialize () : BOOLEAN;

PROCEDURE MaxWidth () : CARDINAL;

PROCEDURE MaxHeight () : CARDINAL;

PROCEDURE Clear;

PROCEDURE SetColour (colour : CARDINAL);

PROCEDURE SetEGAcolour (colour : CARDINAL);

PROCEDURE SetRGB (red, green, blue : CARDINAL);

PROCEDURE DrawLine (x0, y0, dx, dy : CARDINAL);

PROCEDURE Plot (x, y : CARDINAL);

PROCEDURE ThisColour (x, y : CARDINAL) : CARDINAL;

PROCEDURE SetMode (newmode : CARDINAL);

PROCEDURE GetMode () : CARDINAL;

PROCEDURE GetKey (VAR ch : CHAR);

END Vga.
   

Changes to the Mocka compiler

Below, I list the changes to the respective scripts such that Mocka will incorporate the right modules in the linking phase. You need to change just two script files. Remember to do this as 'root' user, otherwise the scripts might not run anymore.

First locate the files 'MC' and '???/sys/link' using the 'locate' command. Switch to the directory that contains the 'MC' script. Then issue the command:

bash-2.05# cp MC GMC
Edit the file as described below. You only need to add ONE token to GMC.

File : /usr/local/bin/MC

Change the line reading

LINK=${MCLINK-$MOCKADIR/sys/link}
into
LINK=${MCLINK-$MOCKADIR/sys/glink}
Now that we have changed the Integrated Development Environment (IDE) such that another linker mechanism has been chosen, we also need to appropriately instruct the linker. That's done in the file in 'sys/glink'.

But first you need to create that file. Locate the file using something similar to:

     bash-2.05# locate /sys/link
     /usr/local/mocka/sys/link
   
Now create the file 'glink' as follows:
bash-2.05# cp link glink
You only need to change the bottom line of that file to something similar to:
$LD -o $program -lvga $STAT $PRE $RTS $modules $LIB $POST

Rounding up

Well, that's it. If you want to write executables that use SVGAlib graphics in them, just start the Mocka compiler using 'GMC' and do your thing. Don't forget that SVGAlib programs must be SUID root before they can run since there are some special instructions in the Initialize section of SVGAlib. To do that, change to user root and do as follows:

     bash-2.05# chown root:root [filename]
     bash-2.05# chmod 4755 [filename]
   
This should do the trick.

The current contents of the VGA module is just for testing. If you have ideas for additions or omissions, don't hesitate to implement them. Please report your problems and progress on

A pleasant side effect.

While running some tests to try out graphic mode, I found a strange but pleasant side effect of using the SVGAlib library. Look at the following source and visualize what will happen:

MODULE ttt;

FROM  InOut     IMPORT  Read, Write, WriteLn;

VAR   ch   		: CHAR;

BEGIN
   LOOP
      Read (ch);
      IF  ch = 'X'  THEN  EXIT  END
   END;
   Write (ch);
   WriteLn;
END ttt.
   
Not too difficult, I think. The program enters an infinite loop and it gets out of it if the 'X' (capital 'x') is pressed. But since Unix runs with buffered I/O, you can enter what you like, nothing will happen before you have pressed the Enter key.
No big deal; this is what we KNOW about Unix and we got used to it.

Enter the following source:

MODULE svg01;

FROM  InOut      IMPORT  Read, Write, WriteBf, WriteString;

IMPORT Vga;

VAR   OldMode, x, y		: CARDINAL;
      ch			: CHAR;

BEGIN
   IF  Vga.Initialize () = FALSE  THEN
      WriteString ('Could not start SVGAlib libraries. Aborting...');
      WriteBf;
      HALT
   END;
   OldMode := Vga.GetMode ();
   Vga.SetMode (4);
   Vga.SetColour (14);
   Vga.Clear ();
   Vga.SetColour (10);
   FOR y := 125 TO 175 DO
      FOR x := 100 TO 500 DO
         Vga.Plot (x, y)
      END
   END;
   LOOP
      Read (ch);
      IF  ch = 'X'  THEN  EXIT  END
   END;
   Vga.SetMode (OldMode);
   Write (ch);
   WriteBf;
END svg01.
   
This program does a bit more. It initializes the SVGAlib functions and it paints a nice geometrical shape on the screen. It was nice to see how fast it worked. And it proves the power of Mocka as a Modula-2 compiler. The 'FOREIGN MODULES' are very powerful.

But now compile and run this program (with the GMC script). What do you think will happen after the shape is drawn on screen?

I'll tell you: the 'Read' function suddenly doesn't need an Enter key to access the keys you type! Apparently, 'Read' suddenly reads from an -unbuffered- inputstream!
Just try it. Run the program and touch some keys. Nothing happens, as usual. But as soon as you hit the capital 'X', the program jumps out of its loop and resumes execution.

This opens up a lot of opportunities. Now we won't need the SVGA 'raw' keyboard functions anymore. Cooked will do just as well for us!

Page created 2004,