LCD simulator with Xlib

Hello folks,

I am developing a library to interface graphical displays (TFTs) and touchscreens with microcontrollers, also providing a simple GUI toolkit. To make the development easier, I’d like to create a simple display simulator so I can develop everything on my computer without the need of physical hardware in order to try it out and debug it.
I thought it should be possible to do this quite easily using Xlib and OpenGL (I am on a linux machine). I need the Xlib in order to create the window as well as to get the events from the mouse to simulate a touchscreen input.

Now to my problem: I guess I am misunderstanding the “workflow” in which Xlib and OpenGL work together. My driver API looks like the following:


void gdisp_lld_init(void);  // here I create the window and set everything else up
void gdisp_lld_clear(color_t color);
void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color);
void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
...

Now, after I get the window created in the init routine, I thought I would be able to simply draw something within the glBegin() and glEnd() calls and then I simply redraw the screen, without deleting the old content. However, I don’t really understand how this should be done. My main problem is that I don’t really see how I can just tell OpenGL to redraw the scene without deleting the old content.
I found this example[1], but there, the content is always redrawn when the display is supposed to be refreshed. This is not what I want. I want to be able to add a drawing without the need to redraw the old content.

So, can anyone tell me what’s the way to archive what I want?

Thanks in advance,

~ Tectu

[1] ht tp://www-f9.ijs.si/~matevz/docs/007-2392-003/sgi_html/ch03.html#LE92780-PARENT

My main problem is that I don’t really see how I can just tell OpenGL to redraw the scene without deleting the old content.

Uhm, OpenGL only clears the framebuffer if told to do so, i.e. by calling glClear(/* mask to specify buffers to clear */). Perhaps I don’t understand what you want to do, but it seems to me you only have to not call glClear() - oh, also if you use double buffering you have to make sure to apply all drawing operations to both buffers (or copy buffer content), otherwise the next buffer swap will show differences.

I am not using double buffering so this shouldn’t be the issue so far.

From the example I linked in my first post, I hacked together this:


#include "ch.h"
#include "hal.h"
#include "gfx.h"

#ifdef GFX_USE_GDISP /* || defined(__DOXYGEN__) */

#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>

#ifndef GDISP_SCREEN_WIDTH
	#define GDISP_SCREEN_WIDTH	640
#endif
#ifndef GDISP_SCREEN_HEIGHT
	#define GDISP_SCREEN_HEIGHT	480
#endif

Display                 *dpy;
Window                  win;
XVisualInfo				*vi;
XSetWindowAttributes	swa;
GLXContext				cx;
XEvent					event;

int attributeList[] =	{ GLX_RGBA, None };

/* the memory for our thread */
static WORKING_AREA(myThreadWorkingArea, 10240);

/* the actual thread */
static msg_t myThread(void *arg)
{
	(void)arg;

	chRegSetThreadName("X11 Thread");	

	while ( 1 ) {
    	do { 
    	    char buf[31];
    	    KeySym keysym;
	
    	    XNextEvent(dpy, &event);
    	    switch(event.type)
			{
    	    	case Expose:
            		/* redraw the screen here? */
					break;
			}

		} while (XPending(dpy));
	}

	return 0;
}

bool_t gdisp_lld_init(void)
{
	/* open the new display but don't show it up yet */
	dpy = XOpenDisplay(NULL);
	if(dpy == NULL) {
		fprintf(stdout, "Couldn't connect to the X server
");
		return false;
	}

	/* get an appropriate visual */
	vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
	if(vi == NULL) {
		fprintf(stdout, "No appropriate visual found. Check your attributes!
");
		return false;
	}

	/* create a GLX context */
	cx = glXCreateContext(dpy, vi, 0, GL_TRUE);

	/*create a colormap */
	swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone);

	/* create a window */
	swa.border_pixel = 0;
	swa.event_mask = ExposureMask;
	win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, 0,
						vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);
	XStoreName(dpy, win, "ChibiOS/GFX");
	XMapWindow(dpy, win);

	/* connect the context to the window */
	glXMakeCurrent(dpy, win, cx);

	/* create the OpenGL thread */
	chThdCreateStatic(myThreadWorkingArea, sizeof(myThreadWorkingArea), NORMALPRIO, myThread, NULL);

	return 0;
}

void gdisp_lld_clear(color_t color) {
	glClearColor( (float)RED_OF(color), (float)GREEN_OF(color), (float)BLUE_OF(color), 1.0f );
	glClearColor( 1.0f, 0.0f, 1.0f, 1.0f);
	glClear( GL_COLOR_BUFFER_BIT );
}

void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
	glBegin( GL_POINTS );
		glVertex2i( 10, 10 );
		glVertex2i( 50, 50 );
	glEnd();
}

void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
	/* ToD o*/
}

#endif /* GFX_USE_GDISP */

The line chThdCreateStatic() create a thread (I am working inside an RTOS simulator) which is supposed to handle all the events and redraw the screen if necessary. As you can see, I also don’t clear the GL buffer (unless the driver is supposed to do so when calling gdisp_lld_clear().
When I run that code, nothing really happens. I do get the window but it’s “transparent” (it has the content of the underlying window and keeps that one). Nothing changes even when I call the clear and the draw_pixel routine.

What am I missing here?

~ Tectu

From the wiki:

In order for any OpenGL commands to work, a context must be current; all OpenGL commands affect the state of whichever context is current. The current context is a thread-local variable, so a single process can have several threads, each of which has its own current context. However, a single context cannot be current in multiple threads at the same time.

I tried to set the current context as it should be. However, I guess my main problem is that I don’t understand the «workflow» properly in how OpenGL and my window system (X) are supposed to work together. Could you give me some step-by-step in what to do? As in:

[ol]
[li]Create display
[/li][li]Create context
[/li][li]Create window
[/li][li]Set current context
[/li][li]Do some drawing
[/li][li]Then some refreshing maybe?
[/li][/ol]

~ Tectu

I normally don’t use X directly (but some toolkit like Qt, GTK or for simple stuff GLUT), so I don’t have code for that, but other folks do: OpenGL with X11 Example :wink:

Thanks for the link. But that one has the same issue again: When it’s exposed, it simply does call all the actual drawing (renderGL()). In my case, I would need to add drawings at any time, and then display them without a refresh. From all the demo codes I’ve now seen it looks like I have to queue/store my drawing operations and when being exposed, simply work through the list and draw everything?!

~ Tectu

I guess. Or you could use double buffering and use the back buffer to accumulate your drawing operations and when you want to show them swap buffers. Although I’m not sure that really does what you are looking for - I’m realising I don’t fully understand the problem and constraints you are working with :-/

Well, the problem I am dealing with is, that I don’t know what I want to draw at compile time. While run time of the program, a part of the program tells “now, draw a pixel at in red color at 13/37” and maybe half an hour later, it says “yeah cool, now let’s draw a green pixel at location 52/98”. I’d then like to see both pixels.
All the examples I’ve seen know while compile time what they are going to draw.

~ Tectu

In that case, yes, you’ll need some way to keep track of what makes up your “scene”, i.e. the set of graphical objects.

Sounds like an abstract base class for drawable objects from which you derive a bunch of concrete classes for different kinds of objects and a container that stores pointers to the base type could fit the bill:


class Drawable
{
public:
   virtual void draw(void) const = 0;
};

class Box : public Drawable
{
public:
   virtual void draw(void) const;
};

typedef std::vector<Drawable*> DrawableStore;

void
drawScene(const DrawableStore& scene)
{
    DrawableStore::const_iterator dIt  = scene.begin();
    DrawableStore::const_iterator dEnd = scene.end();

    for(; dIt != dEnd; ++dIt)
        dIt->draw();
}