How to Create a Game Loop with Xlib

How to create a game loop with xlib

Communicating directly with Xlib is so early-90s (read: noone has done this, unless he's a framework designer, in the last 20 years!).

You're right, looping through pixels to update them on the screen is incredibly slow. That's why almost all modern GUI Frameworks use their own Xbuffers that they just draw on and instruct X to render.

As a comment on your approach:
Game development on raw X doesn't make the least sense, as there are more protable, better performing, easier to use, small, well-tested libraries. Take SDL as an example.

Update March 2021: As Pablo Ariel pointed out below, it might be important by now to point out that investing time in learning X11 isn't the wises investment by now: X is going away; it took a few decades, but the largest Linux distros (after Debian 10 does that, Ubuntu 21.04 does too, and thus all derivates like Mint use Wayland by default; Fedora 34 does the same) are using Wayland by default; using X11 is still possible on these, but it's an extra step to use something old...

Note that this doesn't mean Wayland is what you should learn if you're trying to learn how to produce games. Or raw OpenGL. Or Vulkan. A graphics/game engine is your friend, because you a) don't want to deal with all the low-level stuff yourself of abstracting the subtle differences between different versions of the same thing, and b) you're not getting any faster than a well-written enginge, and the people writing game engines are going to be better than you at that. Concentrate on the relevant part, not on dealing with lowest-level libraries!

X11 : How to Render Continuously

The expose event just tells you that a part of the window which was previously obscured is now visible, so you might need to redraw. There is no restriction that you redraw only at expose events.

How to draw rectangle using Qt to Xlib window

You could embed this window, place an invisible window on top and render into this invisible window. The effect would be the same : a rectangle over the window.

Xlib - window is not rendering

As I wrote before, there's a lot more to X11 than just create a window, paint some lines on it and expect output. You must setup the X event loop to receive events, handle at a minumum exposure events, but also keyboard, mouse, etc. in the proper way. So I'm afraid it's not a bug, it's a design flaw in your program.

For a short tutorial, see here.

What is the best way to organize code for a simple game for X11 and Win32

Games are rarely intrinsically platform dependent. Simple games can be made with GLUT and it is very easy to maintain two versions of the code using #defines. The callbacks are handled by GLUT.

In this way GLUT will enable you write nearly the same code for Windows and Linux. (Because issues such as making the context are already handled by GLUT).

Unless your project is to explicitly re-write GLUT, I recommend you stick with it and get on with writing your game.

Simple C Program that creates 2 X11 windows

It's not a bug, it's a feature. You left out the event loop.

Although you cleverly called XNextEvent twice, the X protocol is asynchronous so the server may still be setting up the actual window while you call XNextEvent, so there is nothing to do.

Tutorial here.

How to stop an X11 event loop gracefully asynchronously

According to these pages

  • how to quit the blocking of xlib's XNextEvent
  • http://www.linuxquestions.org/questions/programming-9/xnextevent-select-409355/#post2431460

The best solution would be perform a select on the X event queue socket
getting the socket is achieved by

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

Display *dis;
Window win;
int x11_fd;
fd_set in_fds;

struct timeval tv;
XEvent ev;

int main() {
dis = XOpenDisplay(NULL);
win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 256, 256,\
0, BlackPixel (dis, 0), BlackPixel(dis, 0));

// You don't need all of these. Make the mask as you normally would.
XSelectInput(dis, win,
ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
ButtonPressMask | ButtonReleaseMask | StructureNotifyMask
);

XMapWindow(dis, win);
XFlush(dis);

// This returns the FD of the X11 display (or something like that)
x11_fd = ConnectionNumber(dis);

// Main loop
while(1) {
// Create a File Description Set containing x11_fd
FD_ZERO(&in_fds);
FD_SET(x11_fd, &in_fds);

// Set our timer. One second sounds good.
tv.tv_usec = 0;
tv.tv_sec = 1;

// Wait for X Event or a Timer
if (select(x11_fd+1, &in_fds, 0, 0, &tv))
printf("Event Received!\n");
else
// Handle timer here
printf("Timer Fired!\n");

// Handle XEvents and flush the input
while(XPending(dis))
XNextEvent(dis, &ev);
}
return(0);
}

What is the most efficient way to put multiple colours on a window, especially in frame-by-frame format?

After three or so more weeks of testing things off and on, I finally figured out how to do it, and it was rather simple. As I said in the OP, XAllocColor and XSetForground take quite a bit of time (relatively) to work. XDrawPoint also was slow, as it does more than just put a pixel at a point on an image.

First I tested how Xlib's colour format works (for the unsigned long int represented as pixel.pixel, which was what I needed XAllocColor for), and it appears to have 100% red set to 16711680, 100% green set to 65280, and 100% blue set to 255, which is obviously a pattern. I found the maximum to be a 50% of all colours, 4286019447, which is a solid grey.

Next, I made sure my XVisualInfo would be supported by my system with a test using XMatchVisualInfo([expected visual info values]). That ensures the depth I will use and the TrueColor class works.

Finally, I made an XImage copied from the root window's image for manipulation. I used XPutPixel for each pixel on the window and set it to a random value between 0 and 4286019448, creating the random image. I then used XPutImage to paste the image to the window.

Here's the final code:

if (!XMatchVisualInfo(display, screenNumber, 24, TrueColor, &visualInfo)) {
exit(0);
}
frameImage = XGetImage(display, rootWindow, 0, 0, screenWidth, screenHeight, AllPlanes, ZPixmap);
while (1) {
for (unsigned short x = 0; x < currentWindowWidth; x += pixelSize) {
for (unsigned short y = 0; y < currentWindowHeight; y += pixelSize) {
XPutPixel(frameImage, x, y, rand() % 4286019447);
}
}
XPutImage(display, window, graphics, frameImage, 0, 0, 0, 0, currentWindowWidth, currentWindowHeight);
}

This puts a random image on the screen, at a stable 140 frames per second on fullscreen. I don't necessarily know if this is the most efficient way, but it works way better than anything else I've tried. Let me know if there is any way to make it better.



Related Topics



Leave a reply



Submit