Console Graphics

Do you ever miss the good-old child times where you get BASIC or LOGO, and a screen for whatever you like to draw?  Here is how you can do it with SVGAlib.  In addition to FreeBSD, the code can be run elsewhere, I mean hmm…  So now you can program without even using X11.

Installing the Library

Here is how the library can be installed on FreeBSD. As of today, the library has no dependencies. It talks to the kernel console device directly.

pkg install svgalib

Writing the Code

Here is the code I tried on FreeBSD. I wrote a clock, in a childish way. Factorisation would be trivial so I do not make it. Since the clock is rotating clockwise from the top, instead of anticlockwise from the left, the angle has to be inverted and skewed. Also, in computer graphics, the higher the Y value, the lower the point; therefore the variable y2 is flipped when drawing the clock hands.

#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <vga.h>
  
int main(void){
 const int screen_width = 320;
 const int screen_height = 240;
 const int screen_mode = G320x240x256;
 const int clock_radius = 100;
 const int hour_length = 40;
 const int minute_length = 80;
 const int second_length = 70;
 const int screen_centre = screen_width / 2;
 const int screen_middle = screen_height / 2;
 const float pi = 3.1415926536;
 const float step = 0.1;
 int x1, x2, y1, y2, i;
 float angle;
 struct timeval tv;
 struct tm* tm;
 long now;
  
 if (vga_init() < 0)
  return EXIT_FAILURE;
 vga_setmode(screen_mode);
  
 /* Loop until a key is pressed */
 for (; vga_getkey() == 0; ) {
  /* Draw the clock face, that is, a circle. */
  vga_setcolor(15);
  x1 = screen_centre + clock_radius * cos(0);
  y1 = screen_middle + clock_radius * sin(0);
  for (angle = step; angle < 2 * pi; angle += step) {
   x2 = screen_centre + clock_radius * cos(angle);
   y2 = screen_middle + clock_radius * sin(angle);
   vga_drawline(x1, y1, x2, y2);
   x1 = x2;
   y1 = y2;
  }
  x1 = screen_centre + clock_radius * cos(0);
  y1 = screen_middle + clock_radius * sin(0);
  vga_drawline(x1, y1, x2, y2);
  
  /* Get the current time and convert it to local */
  gettimeofday(&tv, NULL);
  tm = localtime(&(tv.tv_sec));
  now = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
  
  /* Set the centre of the clock */
  x1 = screen_centre;
  y1 = screen_middle;
  
  /* Draw the hour hand */
  angle = 2 * pi * (now % 43200) / 43200;
  angle = -1 * angle + pi / 2;
  vga_setcolor(15);
  x2 = screen_centre + hour_length * cos(angle);
  y2 = screen_middle - hour_length * sin(angle);
  vga_drawline(x1, y1, x2, y2);
  
  /* Draw the minute hand */
  angle = 2 * pi * (now % 3600) / 3600;
  angle = -1 * angle + pi / 2;
  vga_setcolor(15);
  x2 = screen_centre + minute_length * cos(angle);
  y2 = screen_middle - minute_length * sin(angle);
  vga_drawline(x1, y1, x2, y2);
  
  /* Draw the second hand */
  angle = 2 * pi * (now % 60) / 60;
  angle = -1 * angle + pi / 2;
  vga_setcolor(4);
  x2 = screen_centre + second_length * cos(angle);
  y2 = screen_middle - second_length * sin(angle);
  vga_drawline(x1, y1, x2, y2);
  
  /* Keep the screen for some time and refresh */
  sleep(1);
  //vga_clear();
 }
  
 vga_setmode(TEXT);
 return EXIT_SUCCESS;
}

Compiling the Code

Here is how the code can be compiled on FreeBSD, with the C Shell.  If you are using some other shell, it could be “export x=y” instead of “setenv x y”.

setenv CPATH /usr/local/include
setenv LIBRARY_PATH /usr/local/lib
cc -O2 -pipe hello.c -o hello -lvga -lm

The Outcome

svgaclock

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s