player: x11 bitmap window

This commit is contained in:
veclavtlica
2026-08-12 13:28:18 +03:00
commit 2e890fb5b7
6 changed files with 154 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
**/*.o
*.sublime-*
Player/player
+2
View File
@@ -0,0 +1,2 @@
extern int plr_display_x11_main(int argc, char *argv[]);
+120
View File
@@ -0,0 +1,120 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "display.h"
bool quited = false;
#define WIDTH 640
#define HEIGHT 480
// TODO: correct error handling.
extern int plr_display_x11_main(int argc, char *argv[])
{
Display *display = XOpenDisplay(NULL);
if (NULL == display) {
fprintf(stderr, "Failed to initialize display");
return EXIT_FAILURE;
}
Window root = DefaultRootWindow(display);
if (None == root) {
fprintf(stderr, "No root window found");
XCloseDisplay(display);
return EXIT_FAILURE;
}
int screen = DefaultScreen(display);
Visual *visual = DefaultVisual(display, screen);
int depth = DefaultDepth(display, screen);
Window window = XCreateSimpleWindow(display, root, 0, 0, WIDTH, HEIGHT, 0, 0, 0xffffffff);
if (None == window) {
fprintf(stderr, "Failed to create window");
XCloseDisplay(display);
return EXIT_FAILURE;
}
XSizeHints *hints = XAllocSizeHints();
if (hints == NULL) return EXIT_FAILURE;
// Pinning min and max to the same values disables resizing
hints->flags = PMinSize | PMaxSize;
hints->min_width = hints->max_width = WIDTH;
hints->min_height = hints->max_height = HEIGHT;
XSetWMNormalHints(display, window, hints);
XFree(hints);
XSelectInput(display, window, ExposureMask | KeyPressMask);
XMapWindow(display, window);
GC gc = XCreateGC(display, window, 0, NULL);
Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, & wm_delete_window, 1);
// TODO: can't be not true
int bytes_per_pixel = 4;
char *pixel_buffer = (char *)malloc(WIDTH * HEIGHT * bytes_per_pixel);
XImage *ximage = XCreateImage(
display, visual, depth, ZPixmap, 0,
pixel_buffer, WIDTH, HEIGHT, 32, 0
);
if (!ximage) {
fprintf(stderr, "Failed to create XImage\n");
free(pixel_buffer);
XCloseDisplay(display);
return EXIT_FAILURE;
}
int frame = 0;
XEvent event;
while (!quited) {
XNextEvent(display, &event);
switch(event.type) {
case ClientMessage:
if(event.xclient.data.l[0] == wm_delete_window) {
XDestroyWindow(display, window);
quited = true;
}
break;
case Expose:
frame += 2;
// Fill buffer with a simple color gradient
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int pixel_index = (y * WIDTH + x) * bytes_per_pixel;
// Assuming standard Little-Endian 32-bit BGRA format
pixel_buffer[pixel_index + 0] = (x + frame) % 256; // Blue
pixel_buffer[pixel_index + 1] = (y + frame) % 256; // Green
pixel_buffer[pixel_index + 2] = (x + y - frame) % 256; // Red
pixel_buffer[pixel_index + 3] = 0; // Alpha/Padding
}
}
// Draw the complete image onto the window when exposed
XPutImage(
display,
window, // Target drawable
gc, // Graphics Context
ximage, // Source XImage
0, 0, // Source coordinates (x, y)
0, 0, // Destination coordinates (x, y)
WIDTH, HEIGHT// Dimensions to copy
);
break;
}
}
XCloseDisplay(display);
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
CC=clang
CFLAGS=-lX11
DEPS =
OBJ = main.o Display/x11.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
player: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)
+13
View File
@@ -0,0 +1,13 @@
Pustina -- Player
BYOND-inspired optimized web-driven content player.
All logic is processed on the server, whereas player only does display changes and sends unreliable inputs.
This allows for no-update and hidden content strategies, allowing for mystic and truly seamlessly progressing world.
We do not use abstractions, as the simplicity of the required set of features should allow for platform-specific implementations.
Restrictions:
-- Fixed sized frambuffer, default is 640x480, but platforms can implement their own. Scaling by 2 is possible.
-- GIF image format for all drawing purposes. Delta Frame Optimiztion is encouraged.
-- Images are 32x32 or multiples of it, aligning to the grid.
-- 20 FPS display rate.
-- Fonts are in ASCII bitmaps.
-- Audio samples are in vorbis format. Music pieces are written in our own simple tracker format, using the same vorbis samples.
+5
View File
@@ -0,0 +1,5 @@
#include "Display/display.h"
extern int main(int argc, char *argv[]) {
return plr_display_x11_main(argc, argv);
}