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