Last active
June 6, 2022 17:30
-
-
Save skeeto/8c3502ff22693a9a4f0f7b1efe9c4e0c to your computer and use it in GitHub Desktop.
OpenGL mini framebuffer display example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// cc example.c -lX11 -lGL | |
// This is free and unencumbered software released into the public domain. | |
#define GLX_GLXEXT_PROTOTYPES | |
#include <stdio.h> | |
#include <GL/glx.h> | |
#include <X11/Xlib.h> | |
#define WIDTH 256 | |
#define HEIGHT 128 | |
#define SCALE 4 | |
int main(void) | |
{ | |
Display *d = XOpenDisplay(0); | |
if (!d) { | |
fputs("XOpenDisplay\n", stderr); | |
return 1; | |
} | |
static const int attribs[] = { | |
GLX_X_RENDERABLE, True, | |
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |
GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, | |
GLX_RED_SIZE, 8, | |
GLX_GREEN_SIZE, 8, | |
GLX_BLUE_SIZE, 8, | |
GLX_ALPHA_SIZE, 8, | |
GLX_DEPTH_SIZE, 24, | |
GLX_STENCIL_SIZE, 8, | |
GLX_DOUBLEBUFFER, True, | |
GLX_SAMPLE_BUFFERS, 1, | |
GLX_SAMPLES, 4, | |
None | |
}; | |
int fbcount; | |
int screen = DefaultScreen(d); | |
GLXFBConfig *fbcs = glXChooseFBConfig(d, screen, attribs, &fbcount); | |
if (!fbcs || !fbcount) { | |
fputs("glXChooseFBConfig\n", stderr); | |
return 1; | |
} | |
GLXFBConfig fbc = fbcs[0]; | |
XFree(fbcs); | |
XVisualInfo *vi = glXGetVisualFromFBConfig(d, fbc); | |
XSetWindowAttributes swa; | |
swa.colormap = XCreateColormap(d, RootWindow(d, vi->screen), vi->visual, AllocNone); | |
swa.background_pixmap = None; | |
swa.border_pixel = 0; | |
swa.event_mask = StructureNotifyMask; | |
Window win = XCreateWindow(d, RootWindow(d, vi->screen), | |
0, 0, WIDTH*SCALE, HEIGHT*SCALE, | |
0, vi->depth, InputOutput, vi->visual, | |
CWBorderPixel|CWColormap|CWEventMask, &swa); | |
if (!win) { | |
fputs("XCreateWindow\n", stderr); | |
return 1; | |
} | |
XStoreName(d, win, "MCU"); | |
XMapWindow(d, win); | |
GLXContext ctx = glXCreateContext(d, vi, 0, True); | |
XFree(vi); | |
XSync(d, False); | |
if (!ctx) { | |
fputs("glXCreateContext\n", stderr); | |
return 1; | |
} | |
glXMakeCurrent(d, win, ctx); | |
glXSwapIntervalEXT(d, glXGetCurrentDrawable(), 1); | |
GLuint tex; | |
glEnable(GL_TEXTURE_2D); | |
glGenTextures(1, &tex); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
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_MAG_FILTER, GL_NEAREST); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); | |
unsigned long long rng = 1; | |
unsigned char framebuffer[HEIGHT][WIDTH][3]; | |
for (;;) { | |
// Fill framebuffer with random data for demonstration | |
for (int y = 0; y < HEIGHT; y++) { | |
for (int x = 0; x < WIDTH; x++) { | |
rng = rng*0x3243f6a8885a308d + 1; | |
framebuffer[y][x][0] = rng >> 40; | |
framebuffer[y][x][1] = rng >> 48; | |
framebuffer[y][x][2] = rng >> 56; | |
} | |
} | |
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, | |
GL_RGB, GL_UNSIGNED_BYTE, framebuffer); | |
glBegin(GL_QUADS); | |
glVertex2f(-1, -1); glTexCoord2f(0, 0); | |
glVertex2f(-1, +1); glTexCoord2f(1, 0); | |
glVertex2f(+1, +1); glTexCoord2f(1, 1); | |
glVertex2f(+1, -1); glTexCoord2f(0, 1); | |
glEnd(); | |
glXSwapBuffers(d, win); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment