#include <GL/glx.h>
#include <X11/Xlib.h>
#include <alsa/asoundlib.h>
void (*glGenFramebuffers)(GLsizei n, GLuint *framebuffers);
void (*glDeleteFramebuffers)(GLsizei n, GLuint *framebuffers);
void (*glBindFramebuffer)(GLenum target, GLuint framebuffer);
void (*glBindFramebuffer)(GLenum target, GLuint framebuffer);
void (*glFramebufferTexture)(GLenum target, GLenum attachment, GLuint texture,
GLint level);
void (*glDrawBuffers)(GLsizei n, const GLenum *bufs);
int createTexture(unsigned int w, unsigned int h, unsigned int type)
{
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, type, w, h, 0, type, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
return texture;
}
int main()
{
Display *display = XOpenDisplay(NULL);
if (display == NULL)
{
printf("Cannot open display\n");
return 1;
}
int screen = DefaultScreen(display);
Window root = RootWindow(display, screen);
Window window = XCreateSimpleWindow(display, root, 10, 10, 640, 480, 1, 0, 0);
int eventMask =
ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask;
XSelectInput(display, window, eventMask);
XMapWindow(display, window);
Atom deleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(display, window, &deleteWindow, 1);
Atom stateAtom = XInternAtom(display, "_NET_WM_STATE", False);
Atom fullscreenAtom = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
int fullscreen = 0;
snd_pcm_t *pcm_handle;
snd_pcm_open(&pcm_handle, "hw:0,0", SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK);
long unsigned int period_size = 1024;
unsigned int freq = 44100;
unsigned int periods = 2;
int dir = 0;
snd_pcm_hw_params_t *hw_params = NULL;
snd_pcm_hw_params_any(pcm_handle, hw_params);
snd_pcm_hw_params_set_access(pcm_handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &freq, &dir);
snd_pcm_hw_params_set_channels(pcm_handle, hw_params, 2);
snd_pcm_hw_params_set_period_size_near(pcm_handle, hw_params, &period_size,
&dir);
snd_pcm_hw_params_set_periods_min(pcm_handle, hw_params, &periods, &dir);
snd_pcm_hw_params_set_periods_first(pcm_handle, hw_params, &periods, &dir);
snd_pcm_hw_params(pcm_handle, hw_params);
snd_pcm_sw_params_t *sw_params = NULL;
snd_pcm_sw_params_alloca(&sw_params);
snd_pcm_sw_params_current(pcm_handle, sw_params);
snd_pcm_sw_params_set_avail_min(pcm_handle, sw_params, period_size);
snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, 1);
snd_pcm_sw_params(pcm_handle, sw_params);
glGenFramebuffers = (void (*)())glXGetProcAddressARB(
(const unsigned char *)"glGenFramebuffers");
glDeleteFramebuffers = (void (*)())glXGetProcAddressARB(
(const unsigned char *)"glDeleteFramebuffers");
glBindFramebuffer = (void (*)())glXGetProcAddressARB(
(const unsigned char *)"glBindFramebuffer");
glBindFramebuffer = (void (*)())glXGetProcAddressARB(
(const unsigned char *)"glBindFramebuffer");
glFramebufferTexture = (void (*)())glXGetProcAddressARB(
(const unsigned char *)"glFramebufferTexture");
glDrawBuffers =
(void (*)())glXGetProcAddressARB((const unsigned char *)"glDrawBuffers");
int att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
XVisualInfo *vi = glXChooseVisual(display, 0, att);
GLXContext context = glXCreateContext(display, vi, 0, 1);
glXMakeCurrent(display, window, context);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
XWindowAttributes attr;
XGetWindowAttributes(display, window, &attr);
unsigned int backbuffer = createTexture(attr.width, attr.height, GL_RGBA);
unsigned int depthbuffer =
createTexture(attr.width, attr.height, GL_DEPTH_COMPONENT);
unsigned int gbuffer;
glGenFramebuffers(1, &gbuffer);
glBindFramebuffer(GL_FRAMEBUFFER, gbuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, backbuffer, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthbuffer, 0);
glDrawBuffers(2, (GLenum[]){GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT});
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
uint64_t timerCurrent = (time.tv_sec * 10E8 + time.tv_nsec);
uint64_t lag = 0.0;
uint64_t xscreenLag = 0.0;
unsigned int mouseMode = 0;
int mouseX = 0, mouseY = 0, clickX = 0, clickY = 0, deltaX = 0, deltaY = 0;
while (1)
{
XEvent e;
XNextEvent(display, &e);
if (e.type == ClientMessage &&
e.xclient.data.l[0] == (long int)deleteWindow)
break;
if (e.type == MotionNotify && e.xbutton.button == mouseMode - 1)
{
XGrabPointer(display, window, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
XDefineCursor(display, window, None);
mouseX += (deltaX = e.xmotion.x - mouseX);
mouseX += (deltaY = e.xmotion.y - mouseY);
}
else if (e.type == ButtonPress && e.xbutton.button == 1)
{
mouseX = e.xmotion.x;
mouseY = e.xmotion.y;
}
else if (e.type == ButtonRelease && e.xbutton.button == 1 &&
deltaY + deltaY == 0.0f)
{
if (mouseMode != 1) XUngrabPointer(display, CurrentTime);
clickX = e.xmotion.x;
clickY = e.xmotion.y;
}
else if (e.type == KeyPress && e.xkey.keycode == 13 &&
e.xkey.state & Mod1Mask)
{
fullscreen = !fullscreen;
XSendEvent(display, root, False,
SubstructureNotifyMask | SubstructureRedirectMask,
&(XEvent){.xclient.window = window,
.xclient.format = 32,
.xclient.message_type = stateAtom,
.xclient.data.l[0] = fullscreen,
.xclient.data.l[1] = fullscreenAtom,
.xclient.data.l[3] = 1});
}
else if (e.type == KeyPress && e.xkey.keycode == 13 &&
e.xkey.state & Mod1Mask)
{
fullscreen = !fullscreen;
XEvent event = {0};
event.xclient.window = window;
event.xclient.format = 32;
event.xclient.message_type = stateAtom;
event.xclient.data.l[0] = fullscreen;
event.xclient.data.l[1] = fullscreenAtom;
event.xclient.data.l[3] = 1;
XSendEvent(display, root, False,
SubstructureNotifyMask | SubstructureRedirectMask, &event);
}
clock_gettime(CLOCK_MONOTONIC, &time);
uint64_t timerNext = (time.tv_sec * 10E8 + time.tv_nsec);
uint64_t timerDelta = timerNext - timerCurrent;
timerCurrent = timerNext;
xscreenLag += timerDelta;
if (xscreenLag > 30E9)
{
xscreenLag = 0.0;
XResetScreenSaver(display);
}
for (lag += timerDelta; lag >= 1.0 / 60.0; lag -= 1.0 / 60.0)
{
}
clickX = 0, clickY = 0, deltaX = 0, deltaY = 0;
(void)clickX;
(void)clickY;
glBindFramebuffer(GL_FRAMEBUFFER, gbuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glXSwapBuffers(display, window);
}
glDeleteTextures(1, &backbuffer);
glDeleteTextures(1, &depthbuffer);
glDeleteFramebuffers(1, &gbuffer);
XUnmapWindow(display, window);
XDestroyWindow(display, window);
XCloseDisplay(display);
return 0;
}