Wednesday, January 7, 2015

Interactive programming with libvncserver using C

Here I show how you can interactively create a graphical computer program using libvncserver http://libvnc.github.io/ .

Here is a recording of the screen with the program running:



In case you can't see the above video because Blogger uses Flash, use this one instead:

A while ago, I read this post: http://nullprogram.com/blog/2014/12/23/ and learned a simple method how to interactively develop a C program. For this, one compiles code as a shared library and has it continuously reloaded after each recompilation.
Here I will show how you can very easily output images and animations with libvncserver. I plan to use this to show the Fourier transform of camera frames I acquire in a holographic setup. However, that is a longer story and I may explain that sometime later.
Now I will describe the minimal code which is necessary to call libvncserver from a shared library. First I include the appropriate header file. Then I define the data type run_state wich internally represents the VNC server with an element of type rfbScreenInfoPtr. I also declare constants that contain the dimensions of the image.
#include <rfb/rfb.h>

struct run_state{
  rfbScreenInfoPtr server;
};

const  int w=512,h=512;
The function r_init opens a VNC server and allocates memory for the framebuffer.
struct run_state * r_init()
{
  struct run_state *state = malloc(sizeof(*state));
  printf("init\n");
  state->server=rfbGetScreen(0,NULL,w,h,8,3,4);
  if(!state->server)
    return 0;
  state->server->frameBuffer=(char*)malloc(w*h*4);
  state->server->alwaysShared=(1==1);
  rfbInitServer(state->server);

  return state;
}
The following function closes the VNC server. When a modified run.c has been compiled to a new librun.so, the code in main.c (for the link to full source see the bottom of this post) will call in sequence the function r_finalize of the old library and then the r_init the new library. Frankly, it surprised me, that my vncclient nevertheless remains open during a library reload and eventually updates with frames generated by code from the updated librun.so.
void r_finalize(struct run_state *state)
{
  printf("finalize\n");
  rfbShutdownServer(state->server,TRUE);
  free(state->server->frameBuffer);
  rfbScreenCleanup(state->server);
  free(state);
}
This is the last important function r_step. It generates the image to be displayed.
static int count = 0;
int r_step(struct run_state *state)
{
  //  printf("step\n");
  if(!rfbIsActive(state->server))
    return 0;
  int i,j;
  char *b=state->server->frameBuffer;
  for(j=0;j<h;j++)
    for(i=0;i<w;i++){
      int p=4*(i+w*j);
      b[p+0]=b[p+1]=b[p+2]=i%255;
    } 
  char s[100];
  snprintf(s,100,"count: %d\n",count++);
  rfbDrawString(state->server,&radonFont,20,100,s,0xffffff);
  rfbMarkRectAsModified(state->server,0,0,w,h);
  long usec = state->server->deferUpdateTime*1000;
  rfbProcessEvents(state->server,usec);

  return 1; 
}
In the screenshot, at the beginning of this post, the left window shows the image that is generated by r_step. The double loop creates a horizontal gray gradient and in the top left corner is some text with an incrementing counter.

In this post, I only presented a few major snippets of the code. The full source with makefile is in this directory on Github: https://github.com/plops/arduino_due_lisp/tree/3c21d70a9f1b214e39fa3dfb07704c06ed1e2cb9/interactive-display-fft

No comments:

Post a Comment